Merge branch 'develop' of JF/PineTime into master
This commit is contained in:
commit
6c3d6fb257
65
.devcontainer/Dockerfile
Normal file
65
.devcontainer/Dockerfile
Normal file
@ -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
|
60
.devcontainer/README.md
Normal file
60
.devcontainer/README.md
Normal file
@ -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 <yourinterface> -f <nrf52.cfg target file>`
|
||||||
|
|
||||||
|
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
|
78
.devcontainer/build.sh
Normal file
78
.devcontainer/build.sh
Normal file
@ -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!"
|
2
.devcontainer/build_app.sh
Normal file
2
.devcontainer/build_app.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cmake --build /workspaces/Pinetime/build --config Release -- -j6 pinetime-app
|
3
.devcontainer/create_build_openocd.sh
Normal file
3
.devcontainer/create_build_openocd.sh
Normal file
@ -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
|
36
.devcontainer/devcontainer.json
Normal file
36
.devcontainer/devcontainer.json
Normal file
@ -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"
|
||||||
|
}
|
2
.devcontainer/make_build_dir.sh
Normal file
2
.devcontainer/make_build_dir.sh
Normal file
@ -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}
|
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
@ -44,7 +44,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install Embedded Arm Toolchain arm-none-eabi-gcc
|
- name: Install Embedded Arm Toolchain arm-none-eabi-gcc
|
||||||
if: steps.cache-toolchain.outputs.cache-hit != 'true' # Install toolchain if not found in cache
|
if: steps.cache-toolchain.outputs.cache-hit != 'true' # Install toolchain if not found in cache
|
||||||
uses: fiam/arm-none-eabi-gcc@v1.0.2
|
uses: fiam/arm-none-eabi-gcc@v1.0.4
|
||||||
with:
|
with:
|
||||||
# GNU Embedded Toolchain for Arm release name, in the V-YYYY-qZ format (e.g. "9-2019-q4")
|
# GNU Embedded Toolchain for Arm release name, in the V-YYYY-qZ format (e.g. "9-2019-q4")
|
||||||
release: 9-2020-q2
|
release: 9-2020-q2
|
||||||
@ -83,10 +83,11 @@ jobs:
|
|||||||
if: steps.cache-mcuboot.outputs.cache-hit != 'true' # Install MCUBoot if not found in cache
|
if: steps.cache-mcuboot.outputs.cache-hit != 'true' # Install MCUBoot if not found in cache
|
||||||
run: |
|
run: |
|
||||||
cd ${{ runner.temp }}
|
cd ${{ runner.temp }}
|
||||||
git clone --branch v1.5.0 https://github.com/JuulLabs-OSS/mcuboot
|
git clone --branch v1.7.2 https://github.com/mcu-tools/mcuboot
|
||||||
|
|
||||||
- name: Install imgtool dependencies
|
- name: Install imgtool dependencies
|
||||||
run: pip3 install --user -r ${{ runner.temp }}/mcuboot/scripts/requirements.txt
|
run: |
|
||||||
|
pip3 install --user -r ${{ runner.temp }}/mcuboot/scripts/requirements.txt
|
||||||
|
|
||||||
- name: Install adafruit-nrfutil
|
- name: Install adafruit-nrfutil
|
||||||
run: |
|
run: |
|
||||||
@ -99,6 +100,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Checkout source files
|
- name: Checkout source files
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
- name: Show files
|
- name: Show files
|
||||||
run: set ; pwd ; ls -l
|
run: set ; pwd ; ls -l
|
||||||
@ -110,7 +113,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=${{ runner.temp }}/arm-none-eabi -DNRF5_SDK_PATH=${{ runner.temp }}/nrf5_sdk -DUSE_OPENOCD=1 ../
|
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=${{ runner.temp }}/arm-none-eabi -DNRF5_SDK_PATH=${{ runner.temp }}/nrf5_sdk -DUSE_OPENOCD=1 -DBUILD_DFU=1 ../
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
# Make and Upload DFU Package
|
# Make and Upload DFU Package
|
||||||
@ -125,19 +128,10 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
make pinetime-mcuboot-app
|
make pinetime-mcuboot-app
|
||||||
|
|
||||||
- name: Create firmware image
|
- name: Unzip DFU package
|
||||||
run: |
|
run: |
|
||||||
# The generated firmware binary looks like "pinetime-mcuboot-app-0.8.2.bin"
|
|
||||||
ls -l build/src/pinetime-mcuboot-app*.bin
|
|
||||||
${{ runner.temp }}/mcuboot/scripts/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header build/src/pinetime-mcuboot-app*.bin build/src/pinetime-mcuboot-app-img.bin
|
|
||||||
${{ runner.temp }}/mcuboot/scripts/imgtool.py verify build/src/pinetime-mcuboot-app-img.bin
|
|
||||||
|
|
||||||
- name: Create DFU package
|
|
||||||
run: |
|
|
||||||
~/.local/bin/adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/src/pinetime-mcuboot-app-img.bin build/src/pinetime-mcuboot-app-dfu.zip
|
|
||||||
unzip -v build/src/pinetime-mcuboot-app-dfu.zip
|
|
||||||
# Unzip the package because Upload Artifact will zip up the files
|
# Unzip the package because Upload Artifact will zip up the files
|
||||||
unzip build/src/pinetime-mcuboot-app-dfu.zip -d build/src/pinetime-mcuboot-app-dfu
|
unzip build/src/pinetime-mcuboot-app-dfu*.zip -d build/src/pinetime-mcuboot-app-dfu
|
||||||
|
|
||||||
- name: Upload DFU package
|
- name: Upload DFU package
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
# CMake
|
# CMake
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
cmake-*
|
cmake-*/
|
||||||
CMakeFiles
|
CMakeFiles
|
||||||
**/CMakeCache.txt
|
**/CMakeCache.txt
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
|
20
.vscode/c_cpp_properties.json
vendored
Normal file
20
.vscode/c_cpp_properties.json
vendored
Normal file
@ -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
|
||||||
|
}
|
62
.vscode/cmake-variants.json
vendored
Normal file
62
.vscode/cmake-variants.json
vendored
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["ms-vscode.cpptools","ms-vscode.cmake-tools","marus25.cortex-debug"]
|
||||||
|
}
|
64
.vscode/launch.json
vendored
Normal file
64
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
// TODO: find better way to get latest build filename
|
||||||
|
"executable": "./build/src/pinetime-app-1.3.0.out",
|
||||||
|
"name": "Debug OpenOCD ST-LINK pinetime-app-1.3.0.out",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "cortex-debug",
|
||||||
|
"showDevDebugOutput": false,
|
||||||
|
"servertype": "openocd",
|
||||||
|
"runToMain": true,
|
||||||
|
// Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb)
|
||||||
|
"armToolchainPath": "${workspaceRoot}/../gcc-arm-none-eabi-9-2020-q2-update/bin",
|
||||||
|
"svdFile": "${workspaceRoot}/nrf52.svd",
|
||||||
|
"configFiles": [
|
||||||
|
"interface/stlink.cfg",
|
||||||
|
"target/nrf52.cfg"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
64
.vscode/settings.json
vendored
64
.vscode/settings.json
vendored
@ -1,59 +1,9 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||||
"chrono": "cpp",
|
"cmake.configureArgs": [
|
||||||
"list": "cpp",
|
"-DARM_NONE_EABI_TOOLCHAIN_PATH=${env:ARM_NONE_EABI_TOOLCHAIN_PATH}",
|
||||||
"array": "cpp",
|
"-DNRF5_SDK_PATH=${env:NRF5_SDK_PATH}",
|
||||||
"atomic": "cpp",
|
],
|
||||||
"bit": "cpp",
|
"cmake.generator": "Unix Makefiles",
|
||||||
"*.tcc": "cpp",
|
"clang-tidy.buildPath": "build/compile_commands.json"
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
}
|
44
.vscode/tasks.json
vendored
Normal file
44
.vscode/tasks.json
vendored
Normal file
@ -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": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(pinetime VERSION 1.3.0 LANGUAGES C CXX ASM)
|
project(pinetime VERSION 1.4.0 LANGUAGES C CXX ASM)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
@ -21,10 +21,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>")
|
message(FATAL_ERROR "The path to the NRF52 SDK must be specified on the command line (add -DNRF5_SDK_PATH=<path>")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if(NOT USE_JLINK AND NOT USE_GDB_CLIENT AND NOT USE_OPENOCD)
|
|
||||||
set(USE_JLINK true)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_JLINK)
|
if(USE_JLINK)
|
||||||
if (NOT NRFJPROG)
|
if (NOT NRFJPROG)
|
||||||
message(FATAL_ERROR "the path to the tool nrfjprog must be specified on the command line (add -DNRFJPROG=<path>")
|
message(FATAL_ERROR "the path to the tool nrfjprog must be specified on the command line (add -DNRFJPROG=<path>")
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
This contribution guide is in progress, improvements are welcome.
|
|
||||||
|
|
||||||
### Code style
|
|
||||||
|
|
||||||
Any C++ code PRs should aim to follow the style of existing code in the project.
|
|
||||||
|
|
||||||
Using an autoformatter is heavily recommended, but make sure it's configured properly.
|
|
||||||
|
|
||||||
There's currently preconfigured autoformatter rules for:
|
|
||||||
|
|
||||||
* CLion (IntelliJ) in .idea/codeStyles/Project.xml
|
|
||||||
|
|
||||||
You can use those to configure your own IDE if it's not already on the list.
|
|
||||||
|
|
||||||
#### Linting errors and compiler warnings
|
|
||||||
|
|
||||||
Try to avoid any currently enabled warnings and try to reduce the amount of linter errors.
|
|
||||||
|
|
||||||
#### Spelling
|
|
||||||
|
|
||||||
Make sure you spellcheck your code before commiting it.
|
|
||||||
|
|
||||||
#### TODO, FIXME
|
|
||||||
|
|
||||||
Check before commiting that you haven't forgotten anything, preferably don't leave these in your commits.
|
|
||||||
|
|
||||||
#### Licence headers
|
|
||||||
|
|
||||||
You should add your name to the comma-space separated list of contributors if there's a license header.
|
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
By contributing you agree to licence your code under the repository's general license (which is currently GPL-v3+).
|
|
1
CONTRIBUTING.md
Symbolic link
1
CONTRIBUTING.md
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
doc/contribute.md
|
28
README.md
28
README.md
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# PineTime
|
# PineTime
|
||||||
|
|
||||||
[![Build PineTime Firmware](https://github.com/JF002/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/JF002/InfiniTime/actions)
|
[![Build PineTime Firmware](https://github.com/JF002/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/JF002/InfiniTime/actions)
|
||||||
@ -12,6 +11,7 @@
|
|||||||
The **Pinetime** smartwatch is built around the NRF52832 MCU (512KB Flash, 64KB RAM), a 240*240 LCD display driven by the ST7789 controller, an accelerometer, a heart rate sensor, and a vibration motor.
|
The **Pinetime** smartwatch is built around the NRF52832 MCU (512KB Flash, 64KB RAM), a 240*240 LCD display driven by the ST7789 controller, an accelerometer, a heart rate sensor, and a vibration motor.
|
||||||
|
|
||||||
# InfiniTime
|
# InfiniTime
|
||||||
|
|
||||||
![InfiniTime logo](images/infinitime-logo.jpg "InfiniTime Logo")
|
![InfiniTime logo](images/infinitime-logo.jpg "InfiniTime Logo")
|
||||||
|
|
||||||
The goal of this project is to design an open-source firmware for the Pinetime smartwatch :
|
The goal of this project is to design an open-source firmware for the Pinetime smartwatch :
|
||||||
@ -41,24 +41,27 @@ As of now, here is the list of achievements of this project:
|
|||||||
* Brightness settings
|
* Brightness settings
|
||||||
* Flashlight
|
* Flashlight
|
||||||
* Settings
|
* Settings
|
||||||
- 2 watch faces:
|
- 3 watch faces:
|
||||||
* Digital
|
* Digital
|
||||||
* Analog
|
* Analog
|
||||||
|
* [PineTimeStyle](https://wiki.pine64.org/wiki/PineTimeStyle)
|
||||||
- Multiple 'apps' :
|
- Multiple 'apps' :
|
||||||
* Music (control the playback of the music on your phone)
|
* Music (control the playback of music on your phone)
|
||||||
* Heart rate (controls the heart rate sensor and display current heartbeat)
|
* Heart rate (measure your heart rate)
|
||||||
* Navigation (displays navigation instructions coming from the companion app)
|
* Navigation (displays navigation instructions coming from the companion app)
|
||||||
* Notification (displays the last notification received)
|
* Notification (displays the last notification received)
|
||||||
* Paddle (single player pong-like game)
|
* Paddle (single player pong-like game)
|
||||||
* Two (2048 clone game)
|
* Twos (2048 clone game)
|
||||||
* Stopwatch (with all the necessary functions such as play, pause, lap, stop)
|
* Stopwatch
|
||||||
* Motion sensor and step counter (displays the number of steps and the state of the motion sensor in real-time)
|
* Steps (displays the number of steps taken)
|
||||||
|
* Timer (set a countdown timer that will notify you when it expires)
|
||||||
* Metronome (vibrates to a given bpm with a customizable beats per bar)
|
* Metronome (vibrates to a given bpm with a customizable beats per bar)
|
||||||
- User settings:
|
- User settings:
|
||||||
* Display timeout
|
* Display timeout
|
||||||
* Wake-up condition
|
* Wake-up condition
|
||||||
* Time format (12/24h)
|
* Time format (12/24h)
|
||||||
* Default watch face
|
* Default watch face
|
||||||
|
* Daily step goal
|
||||||
* Battery status
|
* Battery status
|
||||||
* Firmware validation
|
* Firmware validation
|
||||||
* System information
|
* System information
|
||||||
@ -73,40 +76,47 @@ As of now, here is the list of achievements of this project:
|
|||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### Getting started
|
### Getting started
|
||||||
|
|
||||||
- [Getting started with InfiniTime 1.0 (quick user guide, update bootloader and InfiniTime,...)](doc/gettingStarted/gettingStarted-1.0.md)
|
- [Getting started with InfiniTime 1.0 (quick user guide, update bootloader and InfiniTime,...)](doc/gettingStarted/gettingStarted-1.0.md)
|
||||||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/ota-gadgetbridge-nrfconnect.md)
|
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/ota-gadgetbridge-nrfconnect.md)
|
||||||
|
|
||||||
### Develop
|
### Develop
|
||||||
|
|
||||||
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||||
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
||||||
|
|
||||||
### Build, flash and debug
|
### Build, flash and debug
|
||||||
|
|
||||||
- [Project branches](doc/branches.md)
|
- [Project branches](doc/branches.md)
|
||||||
- [Versioning](doc/versioning.md)
|
- [Versioning](doc/versioning.md)
|
||||||
- [Files included in the release notes](doc/filesInReleaseNotes.md)
|
- [Files included in the release notes](doc/filesInReleaseNotes.md)
|
||||||
- [Build the project](doc/buildAndProgram.md)
|
- [Build the project](doc/buildAndProgram.md)
|
||||||
- [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md)
|
- [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md)
|
||||||
- [Build the project with Docker](doc/buildWithDocker.md)
|
- [Build the project with Docker](doc/buildWithDocker.md)
|
||||||
|
- [Build the project with VSCode](doc/buildWithVScode.md)
|
||||||
- [Bootloader, OTA and DFU](./bootloader/README.md)
|
- [Bootloader, OTA and DFU](./bootloader/README.md)
|
||||||
- [Stub using NRF52-DK](./doc/PinetimeStubWithNrf52DK.md)
|
- [Stub using NRF52-DK](./doc/PinetimeStubWithNrf52DK.md)
|
||||||
- Logging with JLink RTT.
|
- Logging with JLink RTT.
|
||||||
- Using files from the releases
|
- Using files from the releases
|
||||||
|
|
||||||
### Contribute
|
### Contribute
|
||||||
|
|
||||||
- [How to contribute ?](doc/contribute.md)
|
- [How to contribute ?](doc/contribute.md)
|
||||||
|
|
||||||
### API
|
### API
|
||||||
|
|
||||||
- [BLE implementation and API](./doc/ble.md)
|
- [BLE implementation and API](./doc/ble.md)
|
||||||
|
|
||||||
### Architecture and technical topics
|
### Architecture and technical topics
|
||||||
|
|
||||||
- [Memory analysis](./doc/MemoryAnalysis.md)
|
- [Memory analysis](./doc/MemoryAnalysis.md)
|
||||||
|
|
||||||
### Using the firmware
|
### Using the firmware
|
||||||
|
|
||||||
- [Integration with Gadgetbridge](doc/companionapps/Gadgetbridge.md)
|
- [Integration with Gadgetbridge](doc/companionapps/Gadgetbridge.md)
|
||||||
- [Integration with AmazFish](doc/companionapps/Amazfish.md)
|
- [Integration with AmazFish](doc/companionapps/Amazfish.md)
|
||||||
- [Firmware update, OTA](doc/companionapps/NrfconnectOTA.md)
|
- [Firmware update, OTA](doc/companionapps/NrfconnectOTA.md)
|
||||||
|
|
||||||
|
|
||||||
## TODO - contribute
|
## TODO - contribute
|
||||||
|
|
||||||
This project is far from being finished, and there are still a lot of things to do for this project to become a firmware usable by the general public.
|
This project is far from being finished, and there are still a lot of things to do for this project to become a firmware usable by the general public.
|
||||||
@ -126,6 +136,7 @@ Here a quick list out of my head of things to do for this project:
|
|||||||
Do not hesitate to clone/fork the code, hack it and create pull-requests. I'll do my best to review and merge them :)
|
Do not hesitate to clone/fork the code, hack it and create pull-requests. I'll do my best to review and merge them :)
|
||||||
|
|
||||||
## Licenses
|
## Licenses
|
||||||
|
|
||||||
This project is released under the GNU General Public License version 3 or, at your option, any later version.
|
This project is released under the GNU General Public License version 3 or, at your option, any later version.
|
||||||
|
|
||||||
It integrates the following projects:
|
It integrates the following projects:
|
||||||
@ -135,6 +146,7 @@ It integrates the following projects:
|
|||||||
- Font : **[Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)** under the Apache 2.0 license
|
- Font : **[Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)** under the Apache 2.0 license
|
||||||
|
|
||||||
## Credits
|
## 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 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.
|
||||||
|
|
||||||
Here are some people I would like to highlight:
|
Here are some people I would like to highlight:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Build a stub for PineTime using NRF52-DK
|
# Build a stub for PineTime using NRF52-DK
|
||||||
[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official developpment kit for NRF52832 SoC from Nordic Semiconductor.
|
[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official developpment kit for NRF52832 SoC from Nordic Semiconductor.
|
||||||
|
|
||||||
It can be very useful for PineTime developpment:
|
It can be very useful for PineTime development:
|
||||||
* You can use it embedded JLink SWD programmer/debugger to program and debug you code on the PineTime
|
* You can use it embedded JLink SWD programmer/debugger to program and debug you code on the PineTime
|
||||||
* As it's based on the same SoC than the PineTime, you can program it to actually run the same code than the PineTime.
|
* As it's based on the same SoC than the PineTime, you can program it to actually run the same code than the PineTime.
|
||||||
|
|
||||||
@ -47,4 +47,4 @@ You also need to enable the I/O expander to disconnect pins from buttons and led
|
|||||||
| --------- | --------- |
|
| --------- | --------- |
|
||||||
| DETECT | GND |
|
| DETECT | GND |
|
||||||
|
|
||||||
Now, you should be able to program the SoC on the NRF52-DK board, and use it as if it was running on the pintime.
|
Now, you should be able to program the SoC on the NRF52-DK board, and use it as if it was running on the PineTime.
|
@ -5,9 +5,9 @@ This page describes the BLE implementation and API built in this firmware.
|
|||||||
**Note** : I'm a beginner in BLE related technologies and the information of this document reflect my current knowledge and understanding of the BLE stack. These informations might be erroneous or incomplete. Feel free to submit a PR if you think you can improve these.
|
**Note** : I'm a beginner in BLE related technologies and the information of this document reflect my current knowledge and understanding of the BLE stack. These informations might be erroneous or incomplete. Feel free to submit a PR if you think you can improve these.
|
||||||
|
|
||||||
## BLE Connection
|
## BLE Connection
|
||||||
When starting the firmware start a BLE advertising : it send small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices.
|
When starting the firmware start a BLE advertising : it sends small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices.
|
||||||
|
|
||||||
A companion application (running on a PC, RasberryPi, smartphone) which received this avertising packet can request a connection to the device. This connection procedure allows the 2 devices to negociate communication parameters, security keys,...
|
A companion application (running on a PC, RaspberryPi, smartphone) which received this avertising packet can request a connection to the device. This connection procedure allows the 2 devices to negotiate communication parameters, security keys,...
|
||||||
|
|
||||||
When the connection is established, the pinetime will try to discover services running on the companion application. For now **CTS** (**C**urrent **T**ime **S**ervice) and **ANS** (**A**lert **N**otification **S**ervice) are supported.
|
When the connection is established, the pinetime will try to discover services running on the companion application. For now **CTS** (**C**urrent **T**ime **S**ervice) and **ANS** (**A**lert **N**otification **S**ervice) are supported.
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
The branching model of this project is based on the workflow named [Git flow](https://nvie.com/posts/a-successful-git-branching-model/).
|
The branching model of this project is based on the workflow named [Git flow](https://nvie.com/posts/a-successful-git-branching-model/).
|
||||||
|
|
||||||
It is based on 2 main branches:
|
It is based on 2 main branches:
|
||||||
- **master** : this branch is always ready to be reployed. It means that at any time, we should be able to build the branch and release a new version of the application.
|
- **master** : this branch is always ready to be deployed. It means that at any time, we should be able to build the branch and release a new version of the application.
|
||||||
- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable.
|
- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable.
|
||||||
|
|
||||||
New features should be implemented in **feature branches** created from **develop**. When the feature is ready, a pull-request is created and it'll be merge into **develop** when it is succesfully reviewed and accepted.
|
New features should be implemented in **feature branches** created from **develop**. When the feature is ready, a pull-request is created and it'll be merge into **develop** when it is succesfully reviewed and accepted.
|
||||||
|
@ -163,7 +163,7 @@ J-Link>g
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### JLink RTT
|
#### JLink RTT
|
||||||
RTT is a feature from Segger's JLink devices that allows bidirectionnal communication between the debugger and the target. This feature can be used to get the logs from the embedded software on the development computer.
|
RTT is a feature from Segger's JLink devices that allows bidirectional communication between the debugger and the target. This feature can be used to get the logs from the embedded software on the development computer.
|
||||||
|
|
||||||
- Program the MCU with the code (see above)
|
- Program the MCU with the code (see above)
|
||||||
- Start JLinkExe
|
- Start JLinkExe
|
||||||
|
@ -13,7 +13,7 @@ Based on Ubuntu 18.04 with the following build dependencies:
|
|||||||
|
|
||||||
The `infinitime-build` image contains all the dependencies you need. The default `CMD` will compile sources found in `/sources`, so you need only mount your code.
|
The `infinitime-build` image contains all the dependencies you need. The default `CMD` will compile sources found in `/sources`, so you need only mount your code.
|
||||||
|
|
||||||
This example will build the firmware, generate the MCUBoot image and generate the DFU file. For cloning the repo, see [these instructions](../doc/buildAndProgram.md#clone-the-repo). Outputs will be written to **<project_root>/build/output**:
|
This example will build the firmware, generate the MCUBoot image and generate the DFU file. For cloning the repo, see [these instructions](../doc/buildAndProgram.md#clone-the-repo). Outputs will be written to **<project_root>/build/output**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd <project_root> # e.g. cd ./work/Pinetime
|
cd <project_root> # e.g. cd ./work/Pinetime
|
||||||
|
42
doc/buildWithVScode.md
Normal file
42
doc/buildWithVScode.md
Normal file
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,68 +1,89 @@
|
|||||||
# How to contribute?
|
# How to contribute?
|
||||||
|
|
||||||
## Report bugs
|
## Report bugs
|
||||||
You use your Pinetime and find a bug in the firmware? [Create an issue on Github](https://github.com/JF002/InfiniTime/issues) explaining the bug, how to reproduce it, the version of the firmware you use...
|
|
||||||
|
Have you found a bug in the firmware? [Create an issue on Github](https://github.com/JF002/InfiniTime/issues) explaining the bug, how to reproduce it, the version of the firmware you use...
|
||||||
|
|
||||||
## Write and improve documentation
|
## Write and improve documentation
|
||||||
|
|
||||||
Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, photo, video,...
|
Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, photo, video,...
|
||||||
|
|
||||||
As the documentation is part of the source code, you can submit your improvements to the documentation by submitting a pull request (see below).
|
As the documentation is part of the source code, you can submit your improvements to the documentation by submitting a pull request (see below).
|
||||||
|
|
||||||
## Fix bugs, add functionalities and improve the code
|
## Fix bugs, add functionalities and improve the code
|
||||||
|
|
||||||
You want to fix a bug, add a cool new functionality or improve the code? See *How to submit a pull request below*.
|
You want to fix a bug, add a cool new functionality or improve the code? See *How to submit a pull request below*.
|
||||||
|
|
||||||
## Spread the word
|
## Spread the word
|
||||||
The Pinetime is a cool open source project that deserves to be known. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open-source firmware for a smartwatch!
|
|
||||||
|
The Pinetime is a cool open source project that deserves to be known. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open source firmware for a smartwatch!
|
||||||
|
|
||||||
# How to submit a pull request ?
|
# How to submit a pull request ?
|
||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
|
|
||||||
- Create a branch from develop;
|
- Create a branch from develop;
|
||||||
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...);
|
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...);
|
||||||
- Test your modifications on the actual hardware;
|
- Test your modifications on the actual hardware;
|
||||||
- Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy);
|
- Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy);
|
||||||
- Clean your code and remove files that are not needed;
|
- Clean your code and remove files that are not needed;
|
||||||
- Write documentation related to your new feature is applicable;
|
- Write documentation related to your new feature if applicable;
|
||||||
- Create the pull-request and write a great description about it : what does your PR do, why, how,... Add pictures and video if possible;
|
- Create a pull request and write a great description about it : what does your PR do, why, how,... Add pictures and video if possible;
|
||||||
- Wait for someone to review your PR and take part in the review process;
|
- Wait for someone to review your PR and take part in the review process;
|
||||||
- Your PR will eventually be merged :)
|
- Your PR will eventually be merged :)
|
||||||
|
|
||||||
Your contribution is more than welcome!
|
Your contributions are more than welcome!
|
||||||
|
|
||||||
If you want to fix a bug, add a functionality or improve the code, you'll first need to create a branch from the **develop** branch (see [this page about the branching model](./branches.md)). This branch is called a feature branch, and you should choose a name that explains what you are working on (ex: "add-doc-about-contributions"). In this branch, **focus on only one topic, bug or feature**. For example, if you created this branch to work on the UI of a specific application, do not commit modifications about the SPI driver. If you want to work on multiple topics, create one branch per topic.
|
If you want to fix a bug, add functionality or improve the code, you'll first need to create a branch from the **develop** branch (see [this page about the branching model](./branches.md)). This branch is called a feature branch, and you should choose a name that explains what you are working on (ex: "add-doc-about-contributions"). In this branch, **focus on only one topic, bug or feature**. For example, if you created this branch to work on the UI of a specific application, do not commit modifications about the SPI driver. If you want to work on multiple topics, create one branch for each topic.
|
||||||
|
|
||||||
When your feature branch is ready, **make sure it actually works** and **do not forget to write documentation** about it if it's relevant.
|
When your feature branch is ready, **make sure it actually works** and **do not forget to write documentation** about it if it's relevant.
|
||||||
|
|
||||||
I **strongly discourage to create a PR containing modifications that haven't been tested**. If, for any reason, you cannot test your modifications but want to publish them anyway, **please mention it in the description**. This way, other contributors might be willing to test it and provide feedback about your code.
|
**Creating a pull request containing modifications that haven't been tested is strongly discouraged.** If, for any reason, you cannot test your modifications but want to publish them anyway, **please mention it in the description**. This way, other contributors might be willing to test it and provide feedback about your code.
|
||||||
|
|
||||||
Also, before submitting your PR, check the coding style of your code against the **coding conventions** detailed below. This project also provides [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy) configuration files. You can use them to ensure correct formatting of your code.
|
Also, before submitting your PR, check the coding style of your code against the **coding conventions** detailed below. This project also provides [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy) configuration files. You can use them to ensure correct formatting of your code.
|
||||||
|
|
||||||
Do not forget to check the files you are going to commit and remove those who are not necessary (config files from your IDE, for example). Remove old comments, commented code,...
|
Don't forget to check the files you are going to commit and remove those which aren't necessary (config files from your IDE, for example). Remove old comments, commented code,...
|
||||||
|
|
||||||
Then, you can submit a pull-request for review. Try to **describe your pull request as much as possible**: what did you do in this branch, how does it work, how is it designed, are there any limitations,... This will help the contributors to understand and review your code easily. You can add pictures and video to the description so that contributors will have a quick overview of your work.
|
Then, you can submit a pull request for review. Try to **describe your pull request as much as possible**: what did you do in this branch, how does it work, how it is designed, are there any limitations,... This will help the contributors to understand and review your code easily. You can add pictures and video to the description so that contributors will have a quick overview of your work.
|
||||||
|
|
||||||
Other contributors can post comments about the pull request, maybe ask for more info or adjustments in the code.
|
Other contributors can post comments about the pull request, maybe ask for more info or adjustments in the code.
|
||||||
|
|
||||||
Once the pull request is reviewed and accepted, it'll be merge in **develop** and will be released in the next release version of the firmware.
|
Once the pull request is reviewed and accepted, it'll be merged into **develop** and will be released in the next version of the firmware.
|
||||||
|
|
||||||
## Why all these rules?
|
## Why all these rules?
|
||||||
Reviewing pull-requests is a **very time consuming task** for the creator of this project ([JF002](https://github.com/JF002)) and for other contributors who take the time to review them. Every little thing you do to make their lives easier will **increase the chances your PR will be merge quickly**.
|
|
||||||
|
|
||||||
When reviewing PR, the author and contributors will first look at the **description**. If it's easy to understand what the PR does, why the modification is needed or interesting and how it's done, a good part of the work is already done : we understand the PR and its context.
|
Reviewing pull requests is a **very time consuming task** for the creator of this project ([JF002](https://github.com/JF002)) and for other contributors who take the time to review them. Everything you do to make reviewing easier will **get your PR merged faster**.
|
||||||
|
|
||||||
Then, reviewing **a few files that were modified for a single purpose** is a lot more easier than to review 30 files modified for many reasons (bug fix, UI improvements, typos in doc,...), even if all these changes make sense. Also, it's possible that we agree on some modification but not on some other, and we won't be able to merge the PR because of the changes that are not accepted.
|
When reviewing PRs, the author and contributors will first look at the **description**. If it's easy to understand what the PR does, why the modification is needed or interesting and how it's done, a good part of the work is already done : we understand the PR and its context.
|
||||||
|
|
||||||
We do our best to keep the code as consistent as possible, and that mean we pay attention to the **formatting** of the code. If the code formatting is not consistent with our code base, we'll ask you to review it, which will take more time.
|
Then, reviewing **a few files that were modified for a single purpose** is a lot more easier than to review 30 files modified for many reasons (bug fix, UI improvements, typos in doc,...), even if all these changes make sense. Also, it's possible that we agree on some modification but not on some other, so we won't be able to merge the PR because of the changes that are not accepted.
|
||||||
|
|
||||||
The last step of the review consists in **testing** the modification. If it doesn't work out of the box, we'll ask your to review your code and to ensure that it works as expected.
|
We do our best to keep the code as consistent as possible. If the formatting of the code in your PR is not consistent with our code base, we'll ask you to review it, which will take more time.
|
||||||
|
|
||||||
It's totally normal for a PR to need some more work even after it was created, that's why we review them. But every round trip takes time, and it's good practice to try to reduce them as much as possible by following those simple rules.
|
The last step of the review consists of **testing** the modification. If it doesn't work out of the box, we'll ask your to review your code and to ensure that it works as expected.
|
||||||
|
|
||||||
|
It's totally normal for a PR to need some more work even after it was created, that's why we review them. But every round trip takes time, so it's good practice to try to reduce them as much as possible by following those simple rules.
|
||||||
|
|
||||||
# Coding convention
|
# Coding convention
|
||||||
|
|
||||||
## Language
|
## Language
|
||||||
|
|
||||||
The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction.
|
The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction.
|
||||||
|
|
||||||
It's OK to include C code if this code comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
C code is accepted if it comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
||||||
|
|
||||||
## Coding style
|
## Coding style
|
||||||
|
|
||||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
||||||
|
|
||||||
|
Using an autoformatter is highly recommended, but make sure it's configured properly.
|
||||||
|
|
||||||
|
There are preconfigured autoformatter rules for:
|
||||||
|
|
||||||
|
* CLion (IntelliJ) in .idea/codeStyles/Project.xml
|
||||||
|
|
||||||
|
If there are no preconfigured rules for your IDE, you can use one of the existing ones to configure your IDE.
|
||||||
|
|
||||||
- **Indentation** : 2 spaces, no tabulation
|
- **Indentation** : 2 spaces, no tabulation
|
||||||
- **Opening brace** at the end of the line
|
- **Opening brace** at the end of the line
|
||||||
- **Naming** : Choose self-describing variable name
|
- **Naming** : Choose self-describing variable name
|
||||||
|
@ -18,7 +18,7 @@ This firmware is standalone, meaning that it does not need a bootloader to actua
|
|||||||
**This firmware must be flashed at address 0x00 in the main flash memory**
|
**This firmware must be flashed at address 0x00 in the main flash memory**
|
||||||
|
|
||||||
### Bootloader
|
### Bootloader
|
||||||
The bootloader is maintained by [lupyuen](https://github.com/lupyuen) and is a binary version of [this release](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4).
|
The bootloader is maintained by [lupyuen](https://github.com/lupyuen) and is a binary version of [this release](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4).
|
||||||
|
|
||||||
- **bootloader.hex** : Firmware in Intel HEX file format.
|
- **bootloader.hex** : Firmware in Intel HEX file format.
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
# Getting started with InfiniTime 1.0
|
# Getting started with InfiniTime 1.0
|
||||||
|
|
||||||
On April 22 2021, InfiniTime and Pine64 [announced the release of InfiniTime 1.0](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as *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](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as *enthusiast grade end-user product*. This page aims to guide you with your first step with your new PineTime.
|
||||||
|
|
||||||
## Firmware, InfiniTime, Bootloader, Recovery firmware, OTA, DFU... What is it?
|
## Firmware, InfiniTime, Bootloader, Recovery firmware, OTA, DFU... What is it?
|
||||||
|
|
||||||
You might have already seen these words by reading the announcement, release notes, or [the wiki guide](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0) and, you may find them misleading if you're not familiar with the project.
|
You might have already seen these words by reading the announcement, release notes, or [the wiki guide](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0) and, you may find them misleading if you're not familiar with the project.
|
||||||
|
|
||||||
Basically, a **firmware** is just a software running on the embedded hardware of a device, the PineTime in this case.
|
Basically, a **firmware** is just a software running on the embedded hardware of a device, the PineTime in this case.
|
||||||
@ -13,9 +15,10 @@ Basically, a **firmware** is just a software running on the embedded hardware of
|
|||||||
**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**igital **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).
|
**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**igital **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).
|
||||||
|
|
||||||
## How to check the version of InfiniTime and the bootloader?
|
## How to check the version of InfiniTime and the bootloader?
|
||||||
|
|
||||||
Since September 2020, all PineTimes (devkits or sealed) are flashed using the **[first iteration of the bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7)** and **[InfiniTime 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1)**. There was no recovery firmware at that time.
|
Since September 2020, all PineTimes (devkits or sealed) are flashed using the **[first iteration of the bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7)** and **[InfiniTime 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1)**. There was no recovery firmware at that time.
|
||||||
|
|
||||||
The bootloader only runs when the watch starts (from an empty battery, for example) or after a reset (after a succesful OTA or a manual reset - long push on the button).
|
The bootloader only runs when the watch starts (from an empty battery, for example) or after a reset (after a successful OTA or a manual reset - long push on the button).
|
||||||
|
|
||||||
You can recognize this first iteration of the bootloader with it greenish **PINETIME** logo.
|
You can recognize this first iteration of the bootloader with it greenish **PINETIME** logo.
|
||||||
|
|
||||||
@ -30,14 +33,14 @@ And for version >= 1.0 :
|
|||||||
|
|
||||||
![InfiniTime 1.0 version](version-1.0.jpg)
|
![InfiniTime 1.0 version](version-1.0.jpg)
|
||||||
|
|
||||||
|
PineTime shipped from June 2021 (to be confirmed) will be flashed with the [new version of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0), the [recovery firmware](https://github.com/JF002/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/tag/1.0.0).
|
||||||
PineTime shipped from June 2020 (to be confirmed) will be flashed with the [new version of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0), the [recovery firmware](https://github.com/JF002/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/tag/1.0.0).
|
|
||||||
|
|
||||||
The bootloader is easily recognizable with it white pine cone that is progressively drawn in green. It also displays its own version on the bottom (1.0.0 as of now).
|
The bootloader is easily recognizable with it white pine cone that is progressively drawn in green. It also displays its own version on the bottom (1.0.0 as of now).
|
||||||
|
|
||||||
![Bootloader 1.0](bootloader-1.0.jpg)
|
![Bootloader 1.0](bootloader-1.0.jpg)
|
||||||
|
|
||||||
## How to update your PineTime?
|
## How to update your PineTime?
|
||||||
|
|
||||||
To update your PineTime, you can use one of the compatible companion applications. Here are the main ones:
|
To update your PineTime, you can use one of the compatible companion applications. Here are the main ones:
|
||||||
|
|
||||||
- **[Amazfish](https://github.com/piggz/harbour-amazfish)** (Desktop Linux, mobile Linux, SailfishOS, runs on the PinebookPro and the Pinephone)
|
- **[Amazfish](https://github.com/piggz/harbour-amazfish)** (Desktop Linux, mobile Linux, SailfishOS, runs on the PinebookPro and the Pinephone)
|
||||||
@ -45,9 +48,10 @@ To update your PineTime, you can use one of the compatible companion application
|
|||||||
- **[Siglo](https://github.com/alexr4535/siglo)** (Linux, GTK based)
|
- **[Siglo](https://github.com/alexr4535/siglo)** (Linux, GTK based)
|
||||||
- **NRFConnect** (closed source, Android & iOS).
|
- **NRFConnect** (closed source, Android & iOS).
|
||||||
|
|
||||||
See [this page](ota-gadgetbridge-nrfconnect.md) for more info about the OTA procedure using Gadgetbrige and NRFCOnnect.
|
See [this page](ota-gadgetbridge-nrfconnect.md) for more info about the OTA procedure using Gadgetbridge and NRFConnect.
|
||||||
|
|
||||||
### From InfiniTime 0.7.1 / old bootloader
|
### From InfiniTime 0.7.1 / old bootloader
|
||||||
|
|
||||||
If your PineTime is currently running InfiniTime 0.7.1 and the old bootloader, we strongly recommend you update them to more recent version (Bootloader 1.0.0 and InfiniTime 1.0.0 as of now). We also recommend you install the recovery firmware once the bootloader is up-do-date.
|
If your PineTime is currently running InfiniTime 0.7.1 and the old bootloader, we strongly recommend you update them to more recent version (Bootloader 1.0.0 and InfiniTime 1.0.0 as of now). We also recommend you install the recovery firmware once the bootloader is up-do-date.
|
||||||
|
|
||||||
Using the companion app of your choice, you'll need to apply the OTA procedure for these 3 firmwares in this sequence (failing to follow this specific order might temporarily or permanently brick your device):
|
Using the companion app of your choice, you'll need to apply the OTA procedure for these 3 firmwares in this sequence (failing to follow this specific order might temporarily or permanently brick your device):
|
||||||
@ -59,10 +63,12 @@ Using the companion app of your choice, you'll need to apply the OTA procedure f
|
|||||||
You'll find more info about this process in [this wiki page](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0). You can also see the procedure in video [here](https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529) and [here (from Amazfish)](https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e)
|
You'll find more info about this process in [this wiki page](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0). You can also see the procedure in video [here](https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529) and [here (from Amazfish)](https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e)
|
||||||
|
|
||||||
### From version > 1.0
|
### From version > 1.0
|
||||||
|
|
||||||
If you are already running the new "1.0.0" bootloader, all you have to do is update your version of InfiniTime when it'll be available. We'll write specific instructions when (if) we release a new version of the bootloader.
|
If you are already running the new "1.0.0" bootloader, all you have to do is update your version of InfiniTime when it'll be available. We'll write specific instructions when (if) we release a new version of the bootloader.
|
||||||
|
|
||||||
### Firmware validation
|
### Firmware validation
|
||||||
The bootloader requires a (manual) validation of the firmware. If the watch reset with an updated firmware that was not validated, the bootloader will consider it as non-functionning and will revert to the previous version of the firmware. This is a safety feature to prevent bricking your device with a faulty firmware.
|
|
||||||
|
The bootloader requires a (manual) validation of the firmware. If the watch reset with an updated firmware that was not validated, the bootloader will consider it as non-functioning and will revert to the previous version of the firmware. This is a safety feature to prevent bricking your device with a faulty firmware.
|
||||||
|
|
||||||
You can validate your updated firmware on InfiniTime >= 1.0 by following this simple procedure:
|
You can validate your updated firmware on InfiniTime >= 1.0 by following this simple procedure:
|
||||||
|
|
||||||
@ -74,7 +80,9 @@ You can validate your updated firmware on InfiniTime >= 1.0 by following this si
|
|||||||
- **Reset** to reset the watch and revert to the previously running version of the firmware
|
- **Reset** to reset the watch and revert to the previously running version of the firmware
|
||||||
|
|
||||||
## InfiniTime 1.0 quick user guide
|
## InfiniTime 1.0 quick user guide
|
||||||
|
|
||||||
### Setting the time
|
### Setting the time
|
||||||
|
|
||||||
By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00). The time will be automatically synchronized once you connect on of the companion app to your PineTime using BLE connectivity. InfiniTime does not provide any way to manually set the time for now.
|
By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00). The time will be automatically synchronized once you connect on of the companion app to your PineTime using BLE connectivity. InfiniTime does not provide any way to manually set the time for now.
|
||||||
|
|
||||||
### Navigation in the menu
|
### Navigation in the menu
|
||||||
@ -109,4 +117,3 @@ However, you can enable 2 functionalities using the push button:
|
|||||||
- Push the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
|
- Push the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
|
||||||
|
|
||||||
More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md).
|
More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md).
|
||||||
|
|
||||||
|
BIN
doc/ui/example.png
Normal file
BIN
doc/ui/example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
16
doc/ui_guidelines.md
Normal file
16
doc/ui_guidelines.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# UI design guidelines
|
||||||
|
|
||||||
|
- Align objects all the way to the edge or corner
|
||||||
|
- Buttons should generally be at least 50px high
|
||||||
|
- Buttons should generally be on the bottom edge
|
||||||
|
- Make interactable objects **big**
|
||||||
|
- Recommendations for inner padding, aka distance between buttons:
|
||||||
|
- When aligning 4 objects: 4px, e.g. Settings
|
||||||
|
- When aligning 3 objects: 6px, e.g. App list
|
||||||
|
- When aligning 2 objects: 10px, e.g. Quick settings
|
||||||
|
- When using a page indicator, leave 8px for it on the right side
|
||||||
|
- It is acceptable to leave 8px on the left side as well to center the content
|
||||||
|
- Top bar takes at least 20px + padding
|
||||||
|
- Top bar right icons move 8px to the left when using a page indicator
|
||||||
|
|
||||||
|
![example layouts](./ui/example.png)
|
5
hooks/README.md
Normal file
5
hooks/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Git hooks
|
||||||
|
|
||||||
|
This directory contains Git hooks that simplify contributing to this repository.
|
||||||
|
|
||||||
|
You can install them by copying the files into `.git/hooks` in the repository folder or by running `git config --local core.hooksPath hooks`
|
25
hooks/pre-commit
Executable file
25
hooks/pre-commit
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if clang-format --version | grep -q 'version 11\.'; then
|
||||||
|
CLANG_FORMAT_EXECUTABLE="clang-format"
|
||||||
|
else
|
||||||
|
CLANG_FORMAT_EXECUTABLE="clang-format-11"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v $CLANG_FORMAT_EXECUTABLE &> /dev/null
|
||||||
|
then
|
||||||
|
echo $CLANG_FORMAT_EXECUTABLE does not exist, make sure to install it
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for FILE in $(git diff --cached --name-only)
|
||||||
|
do
|
||||||
|
if [[ "$FILE" =~ src/[A-Za-z0-9\ \-]+*\.(c|h|cpp|cc)$ ]]; then
|
||||||
|
echo Autoformatting $FILE with $CLANG_FORMAT_EXECUTABLE
|
||||||
|
$CLANG_FORMAT_EXECUTABLE -style=file -i -- $FILE
|
||||||
|
git add -- $FILE
|
||||||
|
elif [[ "$FILE" =~ src/(components|displayapp|drivers|heartratetask|logging|systemtask)/.*\.(c|h|cpp|cc)$ ]]; then
|
||||||
|
echo Autoformatting $FILE with $CLANG_FORMAT_EXECUTABLE
|
||||||
|
$CLANG_FORMAT_EXECUTABLE -style=file -i -- $FILE
|
||||||
|
git add -- $FILE
|
||||||
|
fi
|
||||||
|
done
|
@ -418,6 +418,7 @@ list(APPEND SOURCE_FILES
|
|||||||
displayapp/screens/BatteryInfo.cpp
|
displayapp/screens/BatteryInfo.cpp
|
||||||
displayapp/screens/Steps.cpp
|
displayapp/screens/Steps.cpp
|
||||||
displayapp/screens/Timer.cpp
|
displayapp/screens/Timer.cpp
|
||||||
|
displayapp/Colors.cpp
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
displayapp/screens/settings/QuickSettings.cpp
|
displayapp/screens/settings/QuickSettings.cpp
|
||||||
@ -427,6 +428,7 @@ list(APPEND SOURCE_FILES
|
|||||||
displayapp/screens/settings/SettingWakeUp.cpp
|
displayapp/screens/settings/SettingWakeUp.cpp
|
||||||
displayapp/screens/settings/SettingDisplay.cpp
|
displayapp/screens/settings/SettingDisplay.cpp
|
||||||
displayapp/screens/settings/SettingSteps.cpp
|
displayapp/screens/settings/SettingSteps.cpp
|
||||||
|
displayapp/screens/settings/SettingPineTimeStyle.cpp
|
||||||
|
|
||||||
## Watch faces
|
## Watch faces
|
||||||
displayapp/icons/bg_clock.c
|
displayapp/icons/bg_clock.c
|
||||||
@ -495,6 +497,8 @@ list(APPEND SOURCE_FILES
|
|||||||
components/heartrate/Biquad.cpp
|
components/heartrate/Biquad.cpp
|
||||||
components/heartrate/Ptagc.cpp
|
components/heartrate/Ptagc.cpp
|
||||||
components/heartrate/HeartRateController.cpp
|
components/heartrate/HeartRateController.cpp
|
||||||
|
|
||||||
|
touchhandler/TouchHandler.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND RECOVERY_SOURCE_FILES
|
list(APPEND RECOVERY_SOURCE_FILES
|
||||||
@ -552,6 +556,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||||||
components/heartrate/Ptagc.cpp
|
components/heartrate/Ptagc.cpp
|
||||||
components/motor/MotorController.cpp
|
components/motor/MotorController.cpp
|
||||||
components/fs/FS.cpp
|
components/fs/FS.cpp
|
||||||
|
touchhandler/TouchHandler.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND RECOVERYLOADER_SOURCE_FILES
|
list(APPEND RECOVERYLOADER_SOURCE_FILES
|
||||||
@ -607,6 +612,7 @@ set(INCLUDE_FILES
|
|||||||
displayapp/screens/Metronome.h
|
displayapp/screens/Metronome.h
|
||||||
displayapp/screens/Motion.h
|
displayapp/screens/Motion.h
|
||||||
displayapp/screens/Timer.h
|
displayapp/screens/Timer.h
|
||||||
|
displayapp/Colors.h
|
||||||
drivers/St7789.h
|
drivers/St7789.h
|
||||||
drivers/SpiNorFlash.h
|
drivers/SpiNorFlash.h
|
||||||
drivers/SpiMaster.h
|
drivers/SpiMaster.h
|
||||||
@ -660,6 +666,7 @@ set(INCLUDE_FILES
|
|||||||
components/heartrate/Ptagc.h
|
components/heartrate/Ptagc.h
|
||||||
components/heartrate/HeartRateController.h
|
components/heartrate/HeartRateController.h
|
||||||
components/motor/MotorController.h
|
components/motor/MotorController.h
|
||||||
|
touchhandler/TouchHandler.h
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
@ -839,7 +846,7 @@ target_compile_options(${EXECUTABLE_NAME} PUBLIC
|
|||||||
|
|
||||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES
|
set_target_properties(${EXECUTABLE_NAME} PROPERTIES
|
||||||
SUFFIX ".out"
|
SUFFIX ".out"
|
||||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_FILE_NAME}.map"
|
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_FILE_NAME}.map"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${EXECUTABLE_NAME}
|
add_custom_command(TARGET ${EXECUTABLE_NAME}
|
||||||
@ -869,7 +876,7 @@ target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC
|
|||||||
|
|
||||||
set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES
|
set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES
|
||||||
SUFFIX ".out"
|
SUFFIX ".out"
|
||||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map"
|
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
|
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
|
||||||
@ -906,7 +913,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC
|
|||||||
|
|
||||||
set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES
|
set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES
|
||||||
SUFFIX ".out"
|
SUFFIX ".out"
|
||||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map"
|
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME}
|
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME}
|
||||||
@ -936,7 +943,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC
|
|||||||
|
|
||||||
set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES
|
set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES
|
||||||
SUFFIX ".out"
|
SUFFIX ".out"
|
||||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
|
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
|
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
|
||||||
@ -977,7 +984,7 @@ add_dependencies(${EXECUTABLE_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY_MCUBOOT
|
|||||||
|
|
||||||
set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES
|
set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES
|
||||||
SUFFIX ".out"
|
SUFFIX ".out"
|
||||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map"
|
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME}
|
add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME}
|
||||||
@ -1010,7 +1017,7 @@ add_dependencies(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY
|
|||||||
|
|
||||||
set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES
|
set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES
|
||||||
SUFFIX ".out"
|
SUFFIX ".out"
|
||||||
LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map"
|
LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
|
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
|
||||||
|
@ -23,7 +23,6 @@ void Battery::Update() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Non blocking read
|
// Non blocking read
|
||||||
samples = 0;
|
|
||||||
isReading = true;
|
isReading = true;
|
||||||
SaadcInit();
|
SaadcInit();
|
||||||
|
|
||||||
@ -40,9 +39,9 @@ void Battery::SaadcInit() {
|
|||||||
|
|
||||||
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||||
.resistor_n = 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,
|
.reference = NRF_SAADC_REFERENCE_INTERNAL,
|
||||||
.acq_time = NRF_SAADC_ACQTIME_3US,
|
.acq_time = NRF_SAADC_ACQTIME_40US,
|
||||||
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
||||||
.burst = NRF_SAADC_BURST_ENABLED,
|
.burst = NRF_SAADC_BURST_ENABLED,
|
||||||
.pin_p = batteryVoltageAdcInput,
|
.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));
|
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
||||||
|
|
||||||
// A hardware voltage divider divides the battery voltage by 2
|
// A hardware voltage divider divides the battery voltage by 2
|
||||||
// ADC gain is 1/5
|
// ADC gain is 1/4
|
||||||
// thus adc_voltage = battery_voltage / 2 * gain = battery_voltage / 10
|
// thus adc_voltage = battery_voltage / 2 * gain = battery_voltage / 8
|
||||||
// reference_voltage is 0.6V
|
// reference_voltage is 600mV
|
||||||
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
|
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
|
||||||
voltage = p_event->data.done.p_buffer[0] * 6000 / 1024;
|
voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024;
|
||||||
percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
|
|
||||||
percentRemaining = std::max(percentRemaining, 0);
|
|
||||||
percentRemaining = std::min(percentRemaining, 100);
|
|
||||||
percentRemainingBuffer.Insert(percentRemaining);
|
|
||||||
|
|
||||||
samples++;
|
if (voltage > battery_max) {
|
||||||
if (samples > percentRemainingSamples) {
|
percentRemaining = 100;
|
||||||
nrfx_saadc_uninit();
|
} else if (voltage < battery_min) {
|
||||||
isReading = false;
|
percentRemaining = 0;
|
||||||
} else {
|
} else {
|
||||||
nrfx_saadc_sample();
|
percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nrfx_saadc_uninit();
|
||||||
|
isReading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,38 +7,6 @@
|
|||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
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 <int N> 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<uint8_t>(sum / sz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::array<uint8_t, N> 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 {
|
class Battery {
|
||||||
public:
|
public:
|
||||||
Battery();
|
Battery();
|
||||||
@ -47,10 +15,7 @@ namespace Pinetime {
|
|||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
uint8_t PercentRemaining() const {
|
uint8_t PercentRemaining() const {
|
||||||
auto avg = percentRemainingBuffer.GetAverage();
|
return percentRemaining;
|
||||||
avg = std::min(avg, static_cast<uint8_t>(100));
|
|
||||||
avg = std::max(avg, static_cast<uint8_t>(0));
|
|
||||||
return avg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Voltage() const {
|
uint16_t Voltage() const {
|
||||||
@ -69,14 +34,11 @@ namespace Pinetime {
|
|||||||
static Battery* instance;
|
static Battery* instance;
|
||||||
nrf_saadc_value_t saadc_value;
|
nrf_saadc_value_t saadc_value;
|
||||||
|
|
||||||
static constexpr uint8_t percentRemainingSamples = 5;
|
|
||||||
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
|
|
||||||
|
|
||||||
static constexpr uint32_t chargingPin = 12;
|
static constexpr uint32_t chargingPin = 12;
|
||||||
static constexpr uint32_t powerPresentPin = 19;
|
static constexpr uint32_t powerPresentPin = 19;
|
||||||
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
||||||
uint16_t voltage = 0;
|
uint16_t voltage = 0;
|
||||||
int percentRemaining = -1;
|
uint8_t percentRemaining = 0;
|
||||||
|
|
||||||
bool isCharging = false;
|
bool isCharging = false;
|
||||||
bool isPowerPresent = false;
|
bool isPowerPresent = false;
|
||||||
@ -87,7 +49,6 @@ namespace Pinetime {
|
|||||||
static void AdcCallbackStatic(nrfx_saadc_evt_t const* event);
|
static void AdcCallbackStatic(nrfx_saadc_evt_t const* event);
|
||||||
|
|
||||||
bool isReading = false;
|
bool isReading = false;
|
||||||
uint8_t samples = 0;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,9 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||||||
auto time = date::make_time(currentDateTime - dp);
|
auto time = date::make_time(currentDateTime - dp);
|
||||||
auto yearMonthDay = date::year_month_day(dp);
|
auto yearMonthDay = date::year_month_day(dp);
|
||||||
|
|
||||||
year = (int) yearMonthDay.year();
|
year = static_cast<int>(yearMonthDay.year());
|
||||||
month = static_cast<Months>((unsigned) yearMonthDay.month());
|
month = static_cast<Months>(static_cast<unsigned>(yearMonthDay.month()));
|
||||||
day = (unsigned) yearMonthDay.day();
|
day = static_cast<unsigned>(yearMonthDay.day());
|
||||||
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
|
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||||
|
|
||||||
hour = time.hours().count();
|
hour = time.hours().count();
|
||||||
@ -75,31 +75,31 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::MonthShortToString() {
|
const char* DateTime::MonthShortToString() {
|
||||||
return DateTime::MonthsString[(uint8_t) month];
|
return DateTime::MonthsString[static_cast<uint8_t>(month)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::MonthShortToStringLow() {
|
const char* DateTime::MonthShortToStringLow() {
|
||||||
return DateTime::MonthsStringLow[(uint8_t) month];
|
return DateTime::MonthsStringLow[static_cast<uint8_t>(month)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::MonthsToStringLow() {
|
const char* DateTime::MonthsToStringLow() {
|
||||||
return DateTime::MonthsLow[(uint8_t) month];
|
return DateTime::MonthsLow[static_cast<uint8_t>(month)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::DayOfWeekToString() {
|
const char* DateTime::DayOfWeekToString() {
|
||||||
return DateTime::DaysString[(uint8_t) dayOfWeek];
|
return DateTime::DaysString[static_cast<uint8_t>(dayOfWeek)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::DayOfWeekShortToString() {
|
const char* DateTime::DayOfWeekShortToString() {
|
||||||
return DateTime::DaysStringShort[(uint8_t) dayOfWeek];
|
return DateTime::DaysStringShort[static_cast<uint8_t>(dayOfWeek)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::DayOfWeekToStringLow() {
|
const char* DateTime::DayOfWeekToStringLow() {
|
||||||
return DateTime::DaysStringLow[(uint8_t) dayOfWeek];
|
return DateTime::DaysStringLow[static_cast<uint8_t>(dayOfWeek)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DateTime::DayOfWeekShortToStringLow() {
|
const char* DateTime::DayOfWeekShortToStringLow() {
|
||||||
return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek];
|
return DateTime::DaysStringShortLow[static_cast<uint8_t>(dayOfWeek)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
|
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
#include "systemtask/SystemTask.h"
|
#include "systemtask/SystemTask.h"
|
||||||
#include "app_timer.h"
|
#include "app_timer.h"
|
||||||
|
|
||||||
APP_TIMER_DEF(vibTimer);
|
APP_TIMER_DEF(shortVibTimer);
|
||||||
|
APP_TIMER_DEF(longVibTimer);
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
@ -13,19 +14,39 @@ MotorController::MotorController(Controllers::Settings& settingsController) : se
|
|||||||
void MotorController::Init() {
|
void MotorController::Init() {
|
||||||
nrf_gpio_cfg_output(pinMotor);
|
nrf_gpio_cfg_output(pinMotor);
|
||||||
nrf_gpio_pin_set(pinMotor);
|
nrf_gpio_pin_set(pinMotor);
|
||||||
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
|
app_timer_init();
|
||||||
|
|
||||||
|
app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, StopMotor);
|
||||||
|
app_timer_create(&longVibTimer, APP_TIMER_MODE_REPEATED, Ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorController::SetDuration(uint8_t motorDuration) {
|
void MotorController::Ring(void* p_context) {
|
||||||
|
auto* motorController = static_cast<MotorController*>(p_context);
|
||||||
|
motorController->RunForDuration(50);
|
||||||
|
}
|
||||||
|
|
||||||
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF)
|
void MotorController::RunForDuration(uint8_t motorDuration) {
|
||||||
|
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nrf_gpio_pin_clear(pinMotor);
|
nrf_gpio_pin_clear(pinMotor);
|
||||||
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
|
app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr);
|
||||||
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorController::vibrate(void* p_context) {
|
void MotorController::StartRinging() {
|
||||||
|
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ring(this);
|
||||||
|
app_timer_start(longVibTimer, APP_TIMER_TICKS(1000), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MotorController::StopRinging() {
|
||||||
|
app_timer_stop(longVibTimer);
|
||||||
|
nrf_gpio_pin_set(pinMotor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MotorController::StopMotor(void* p_context) {
|
||||||
nrf_gpio_pin_set(pinMotor);
|
nrf_gpio_pin_set(pinMotor);
|
||||||
}
|
}
|
@ -12,11 +12,14 @@ namespace Pinetime {
|
|||||||
public:
|
public:
|
||||||
MotorController(Controllers::Settings& settingsController);
|
MotorController(Controllers::Settings& settingsController);
|
||||||
void Init();
|
void Init();
|
||||||
void SetDuration(uint8_t motorDuration);
|
void RunForDuration(uint8_t motorDuration);
|
||||||
|
void StartRinging();
|
||||||
|
static void StopRinging();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void Ring(void* p_context);
|
||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
static void vibrate(void* p_context);
|
static void StopMotor(void* p_context);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,14 @@ namespace Pinetime {
|
|||||||
DoubleTap = 1,
|
DoubleTap = 1,
|
||||||
RaiseWrist = 2,
|
RaiseWrist = 2,
|
||||||
};
|
};
|
||||||
|
enum class Colors : uint8_t {
|
||||||
|
White, Silver, Gray, Black, Red, Maroon, Yellow, Olive, Lime, Green, Cyan, Teal, Blue, Navy, Magenta, Purple, Orange
|
||||||
|
};
|
||||||
|
struct PineTimeStyle {
|
||||||
|
Colors ColorTime = Colors::Teal;
|
||||||
|
Colors ColorBar = Colors::Teal;
|
||||||
|
Colors ColorBG = Colors::Black;
|
||||||
|
};
|
||||||
|
|
||||||
Settings(Pinetime::Controllers::FS& fs);
|
Settings(Pinetime::Controllers::FS& fs);
|
||||||
|
|
||||||
@ -33,10 +41,38 @@ namespace Pinetime {
|
|||||||
return settings.clockFace;
|
return settings.clockFace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SetPTSColorTime(Colors colorTime) {
|
||||||
|
if (colorTime != settings.PTS.ColorTime)
|
||||||
|
settingsChanged = true;
|
||||||
|
settings.PTS.ColorTime = colorTime;
|
||||||
|
};
|
||||||
|
Colors GetPTSColorTime() const {
|
||||||
|
return settings.PTS.ColorTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetPTSColorBar(Colors colorBar) {
|
||||||
|
if (colorBar != settings.PTS.ColorBar)
|
||||||
|
settingsChanged = true;
|
||||||
|
settings.PTS.ColorBar = colorBar;
|
||||||
|
};
|
||||||
|
Colors GetPTSColorBar() const {
|
||||||
|
return settings.PTS.ColorBar;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetPTSColorBG(Colors colorBG) {
|
||||||
|
if (colorBG != settings.PTS.ColorBG)
|
||||||
|
settingsChanged = true;
|
||||||
|
settings.PTS.ColorBG = colorBG;
|
||||||
|
};
|
||||||
|
Colors GetPTSColorBG() const {
|
||||||
|
return settings.PTS.ColorBG;
|
||||||
|
};
|
||||||
|
|
||||||
void SetAppMenu(uint8_t menu) {
|
void SetAppMenu(uint8_t menu) {
|
||||||
appMenu = menu;
|
appMenu = menu;
|
||||||
};
|
};
|
||||||
uint8_t GetAppMenu() {
|
|
||||||
|
uint8_t GetAppMenu() const {
|
||||||
return appMenu;
|
return appMenu;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,9 +163,8 @@ namespace Pinetime {
|
|||||||
private:
|
private:
|
||||||
Pinetime::Controllers::FS& fs;
|
Pinetime::Controllers::FS& fs;
|
||||||
|
|
||||||
static constexpr uint32_t settingsVersion = 0x0001;
|
static constexpr uint32_t settingsVersion = 0x0002;
|
||||||
struct SettingsData {
|
struct SettingsData {
|
||||||
|
|
||||||
uint32_t version = settingsVersion;
|
uint32_t version = settingsVersion;
|
||||||
uint32_t stepsGoal = 10000;
|
uint32_t stepsGoal = 10000;
|
||||||
uint32_t screenTimeOut = 15000;
|
uint32_t screenTimeOut = 15000;
|
||||||
@ -139,6 +174,8 @@ namespace Pinetime {
|
|||||||
|
|
||||||
uint8_t clockFace = 0;
|
uint8_t clockFace = 0;
|
||||||
|
|
||||||
|
PineTimeStyle PTS;
|
||||||
|
|
||||||
std::bitset<3> wakeUpMode {0};
|
std::bitset<3> wakeUpMode {0};
|
||||||
|
|
||||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||||
|
@ -30,7 +30,8 @@ namespace Pinetime {
|
|||||||
SettingTimeFormat,
|
SettingTimeFormat,
|
||||||
SettingDisplay,
|
SettingDisplay,
|
||||||
SettingWakeUp,
|
SettingWakeUp,
|
||||||
SettingSteps
|
SettingSteps,
|
||||||
|
SettingPineTimeStyle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
src/displayapp/Colors.cpp
Normal file
27
src/displayapp/Colors.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "Colors.h"
|
||||||
|
|
||||||
|
using namespace Pinetime::Applications;
|
||||||
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
|
lv_color_t Pinetime::Applications::Convert(Pinetime::Controllers::Settings::Colors color) {
|
||||||
|
switch (color) {
|
||||||
|
case Pinetime::Controllers::Settings::Colors::White: return LV_COLOR_WHITE;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Silver: return LV_COLOR_SILVER;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Gray: return LV_COLOR_GRAY;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Black: return LV_COLOR_BLACK;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Red: return LV_COLOR_RED;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Maroon: return LV_COLOR_MAROON;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Yellow: return LV_COLOR_YELLOW;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Olive: return LV_COLOR_OLIVE;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Lime: return LV_COLOR_LIME;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Green: return LV_COLOR_GREEN;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Cyan: return LV_COLOR_CYAN;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Teal: return LV_COLOR_TEAL;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Blue: return LV_COLOR_BLUE;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Navy: return LV_COLOR_NAVY;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Magenta: return LV_COLOR_MAGENTA;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Purple: return LV_COLOR_PURPLE;
|
||||||
|
case Pinetime::Controllers::Settings::Colors::Orange: return LV_COLOR_ORANGE;
|
||||||
|
default: return LV_COLOR_WHITE;
|
||||||
|
}
|
||||||
|
}
|
10
src/displayapp/Colors.h
Normal file
10
src/displayapp/Colors.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lvgl/src/lv_misc/lv_color.h>
|
||||||
|
#include <components/settings/Settings.h>
|
||||||
|
|
||||||
|
namespace Pinetime {
|
||||||
|
namespace Applications {
|
||||||
|
lv_color_t Convert(Controllers::Settings::Colors color);
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,7 @@
|
|||||||
#include "displayapp/screens/settings/SettingWakeUp.h"
|
#include "displayapp/screens/settings/SettingWakeUp.h"
|
||||||
#include "displayapp/screens/settings/SettingDisplay.h"
|
#include "displayapp/screens/settings/SettingDisplay.h"
|
||||||
#include "displayapp/screens/settings/SettingSteps.h"
|
#include "displayapp/screens/settings/SettingSteps.h"
|
||||||
|
#include "displayapp/screens/settings/SettingPineTimeStyle.h"
|
||||||
|
|
||||||
#include "libs/lv_conf.h"
|
#include "libs/lv_conf.h"
|
||||||
|
|
||||||
@ -52,6 +53,28 @@ namespace {
|
|||||||
static inline bool in_isr(void) {
|
static inline bool in_isr(void) {
|
||||||
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
|
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TouchEvents ConvertGesture(Pinetime::Drivers::Cst816S::Gestures gesture) {
|
||||||
|
switch (gesture) {
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
||||||
|
return TouchEvents::Tap;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
||||||
|
return TouchEvents::LongTap;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::DoubleTap:
|
||||||
|
return TouchEvents::DoubleTap;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::SlideRight:
|
||||||
|
return TouchEvents::SwipeRight;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::SlideLeft:
|
||||||
|
return TouchEvents::SwipeLeft;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::SlideDown:
|
||||||
|
return TouchEvents::SwipeDown;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::SlideUp:
|
||||||
|
return TouchEvents::SwipeUp;
|
||||||
|
case Pinetime::Drivers::Cst816S::Gestures::None:
|
||||||
|
default:
|
||||||
|
return TouchEvents::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||||
@ -66,7 +89,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::MotorController& motorController,
|
Pinetime::Controllers::MotorController& motorController,
|
||||||
Pinetime::Controllers::MotionController& motionController,
|
Pinetime::Controllers::MotionController& motionController,
|
||||||
Pinetime::Controllers::TimerController& timerController)
|
Pinetime::Controllers::TimerController& timerController,
|
||||||
|
Pinetime::Controllers::TouchHandler& touchHandler)
|
||||||
: lcd {lcd},
|
: lcd {lcd},
|
||||||
lvgl {lvgl},
|
lvgl {lvgl},
|
||||||
touchPanel {touchPanel},
|
touchPanel {touchPanel},
|
||||||
@ -79,7 +103,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||||||
settingsController {settingsController},
|
settingsController {settingsController},
|
||||||
motorController {motorController},
|
motorController {motorController},
|
||||||
motionController {motionController},
|
motionController {motionController},
|
||||||
timerController {timerController} {
|
timerController {timerController},
|
||||||
|
touchHandler {touchHandler} {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::Start() {
|
void DisplayApp::Start() {
|
||||||
@ -140,8 +165,15 @@ void DisplayApp::Refresh() {
|
|||||||
lastWakeTime = xTaskGetTickCount();
|
lastWakeTime = xTaskGetTickCount();
|
||||||
if (messageReceived) {
|
if (messageReceived) {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case Messages::GoToSleep:
|
case Messages::DimScreen:
|
||||||
|
// Backup brightness is the brightness to return to after dimming or sleeping
|
||||||
brightnessController.Backup();
|
brightnessController.Backup();
|
||||||
|
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||||
|
break;
|
||||||
|
case Messages::RestoreBrightness:
|
||||||
|
brightnessController.Restore();
|
||||||
|
break;
|
||||||
|
case Messages::GoToSleep:
|
||||||
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||||
brightnessController.Lower();
|
brightnessController.Lower();
|
||||||
vTaskDelay(100);
|
vTaskDelay(100);
|
||||||
@ -170,7 +202,7 @@ void DisplayApp::Refresh() {
|
|||||||
break;
|
break;
|
||||||
case Messages::TimerDone:
|
case Messages::TimerDone:
|
||||||
if (currentApp == Apps::Timer) {
|
if (currentApp == Apps::Timer) {
|
||||||
auto *timer = static_cast<Screens::Timer*>(currentScreen.get());
|
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
|
||||||
timer->setDone();
|
timer->setDone();
|
||||||
} else {
|
} else {
|
||||||
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
|
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
|
||||||
@ -180,7 +212,7 @@ void DisplayApp::Refresh() {
|
|||||||
if (state != States::Running) {
|
if (state != States::Running) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto gesture = OnTouchEvent();
|
auto gesture = ConvertGesture(touchHandler.GestureGet());
|
||||||
if (gesture == TouchEvents::None) {
|
if (gesture == TouchEvents::None) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -204,7 +236,11 @@ void DisplayApp::Refresh() {
|
|||||||
}
|
}
|
||||||
} else if (returnTouchEvent == gesture) {
|
} else if (returnTouchEvent == gesture) {
|
||||||
LoadApp(returnToApp, returnDirection);
|
LoadApp(returnToApp, returnDirection);
|
||||||
|
brightnessController.Set(settingsController.GetBrightness());
|
||||||
|
brightnessController.Backup();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
touchHandler.CancelTap();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Messages::ButtonPushed:
|
case Messages::ButtonPushed:
|
||||||
@ -213,6 +249,8 @@ void DisplayApp::Refresh() {
|
|||||||
} else {
|
} else {
|
||||||
if (!currentScreen->OnButtonPushed()) {
|
if (!currentScreen->OnButtonPushed()) {
|
||||||
LoadApp(returnToApp, returnDirection);
|
LoadApp(returnToApp, returnDirection);
|
||||||
|
brightnessController.Set(settingsController.GetBrightness());
|
||||||
|
brightnessController.Backup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -227,23 +265,18 @@ void DisplayApp::Refresh() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nextApp != Apps::None) {
|
if (nextApp != Apps::None) {
|
||||||
LoadApp(nextApp, nextDirection);
|
LoadApp(nextApp, nextDirection);
|
||||||
nextApp = Apps::None;
|
nextApp = Apps::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state != States::Idle && touchMode == TouchModes::Polling) {
|
if (touchHandler.IsTouching()) {
|
||||||
auto info = touchPanel.GetTouchInfo();
|
currentScreen->OnTouchEvent(touchHandler.GetX(), touchHandler.GetY());
|
||||||
if (info.action == 2) { // 2 = contact
|
|
||||||
if (!currentScreen->OnTouchEvent(info.x, info.y)) {
|
|
||||||
lvgl.SetNewTapEvent(info.x, info.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::RunningState() {
|
void DisplayApp::RunningState() {
|
||||||
if (!currentScreen->Refresh()) {
|
if (!currentScreen->IsRunning()) {
|
||||||
LoadApp(returnToApp, returnDirection);
|
LoadApp(returnToApp, returnDirection);
|
||||||
}
|
}
|
||||||
lv_task_handler();
|
lv_task_handler();
|
||||||
@ -261,6 +294,7 @@ void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||||
|
touchHandler.CancelTap();
|
||||||
currentScreen.reset(nullptr);
|
currentScreen.reset(nullptr);
|
||||||
SetFullRefresh(direction);
|
SetFullRefresh(direction);
|
||||||
|
|
||||||
@ -295,12 +329,12 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||||||
|
|
||||||
case Apps::Notifications:
|
case Apps::Notifications:
|
||||||
currentScreen = std::make_unique<Screens::Notifications>(
|
currentScreen = std::make_unique<Screens::Notifications>(
|
||||||
this, notificationManager, systemTask->nimble().alertService(), Screens::Notifications::Modes::Normal);
|
this, notificationManager, systemTask->nimble().alertService(), motorController, Screens::Notifications::Modes::Normal);
|
||||||
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||||
break;
|
break;
|
||||||
case Apps::NotificationsPreview:
|
case Apps::NotificationsPreview:
|
||||||
currentScreen = std::make_unique<Screens::Notifications>(
|
currentScreen = std::make_unique<Screens::Notifications>(
|
||||||
this, notificationManager, systemTask->nimble().alertService(), Screens::Notifications::Modes::Preview);
|
this, notificationManager, systemTask->nimble().alertService(), motorController, Screens::Notifications::Modes::Preview);
|
||||||
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||||
break;
|
break;
|
||||||
case Apps::Timer:
|
case Apps::Timer:
|
||||||
@ -337,13 +371,17 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||||||
currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController);
|
currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController);
|
||||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
break;
|
break;
|
||||||
|
case Apps::SettingPineTimeStyle:
|
||||||
|
currentScreen = std::make_unique<Screens::SettingPineTimeStyle>(this, settingsController);
|
||||||
|
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
|
break;
|
||||||
case Apps::BatteryInfo:
|
case Apps::BatteryInfo:
|
||||||
currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController);
|
currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController);
|
||||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
break;
|
break;
|
||||||
case Apps::SysInfo:
|
case Apps::SysInfo:
|
||||||
currentScreen =
|
currentScreen = std::make_unique<Screens::SystemInfo>(
|
||||||
std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController);
|
this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController);
|
||||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||||
break;
|
break;
|
||||||
case Apps::FlashLight:
|
case Apps::FlashLight:
|
||||||
@ -373,6 +411,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||||||
break;
|
break;
|
||||||
case Apps::Metronome:
|
case Apps::Metronome:
|
||||||
currentScreen = std::make_unique<Screens::Metronome>(this, motorController, *systemTask);
|
currentScreen = std::make_unique<Screens::Metronome>(this, motorController, *systemTask);
|
||||||
|
ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::None);
|
||||||
break;
|
break;
|
||||||
case Apps::Motion:
|
case Apps::Motion:
|
||||||
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
|
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
|
||||||
@ -388,7 +427,7 @@ void DisplayApp::IdleState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::PushMessage(Messages msg) {
|
void DisplayApp::PushMessage(Messages msg) {
|
||||||
if(in_isr()) {
|
if (in_isr()) {
|
||||||
BaseType_t xHigherPriorityTaskWoken;
|
BaseType_t xHigherPriorityTaskWoken;
|
||||||
xHigherPriorityTaskWoken = pdFALSE;
|
xHigherPriorityTaskWoken = pdFALSE;
|
||||||
xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken);
|
xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken);
|
||||||
@ -400,35 +439,6 @@ void DisplayApp::PushMessage(Messages msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchEvents DisplayApp::OnTouchEvent() {
|
|
||||||
auto info = touchPanel.GetTouchInfo();
|
|
||||||
if (info.isTouch) {
|
|
||||||
switch (info.gesture) {
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
|
||||||
if (touchMode == TouchModes::Gestures) {
|
|
||||||
lvgl.SetNewTapEvent(info.x, info.y);
|
|
||||||
}
|
|
||||||
return TouchEvents::Tap;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
|
||||||
return TouchEvents::LongTap;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::DoubleTap:
|
|
||||||
return TouchEvents::DoubleTap;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::SlideRight:
|
|
||||||
return TouchEvents::SwipeRight;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::SlideLeft:
|
|
||||||
return TouchEvents::SwipeLeft;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::SlideDown:
|
|
||||||
return TouchEvents::SwipeDown;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::SlideUp:
|
|
||||||
return TouchEvents::SwipeUp;
|
|
||||||
case Pinetime::Drivers::Cst816S::Gestures::None:
|
|
||||||
default:
|
|
||||||
return TouchEvents::None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TouchEvents::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case DisplayApp::FullRefreshDirections::Down:
|
case DisplayApp::FullRefreshDirections::Down:
|
||||||
@ -454,12 +464,8 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
|
|
||||||
touchMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) {
|
void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) {
|
||||||
if(systemTask != nullptr)
|
if (systemTask != nullptr)
|
||||||
systemTask->PushMessage(message);
|
systemTask->PushMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "components/settings/Settings.h"
|
#include "components/settings/Settings.h"
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
#include "components/timer/TimerController.h"
|
#include "components/timer/TimerController.h"
|
||||||
|
#include "touchhandler/TouchHandler.h"
|
||||||
#include "Messages.h"
|
#include "Messages.h"
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
@ -31,6 +32,7 @@ namespace Pinetime {
|
|||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
class HeartRateController;
|
class HeartRateController;
|
||||||
class MotionController;
|
class MotionController;
|
||||||
|
class TouchHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace System {
|
namespace System {
|
||||||
@ -41,7 +43,6 @@ namespace Pinetime {
|
|||||||
public:
|
public:
|
||||||
enum class States { Idle, Running };
|
enum class States { Idle, Running };
|
||||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||||
enum class TouchModes { Gestures, Polling };
|
|
||||||
|
|
||||||
DisplayApp(Drivers::St7789& lcd,
|
DisplayApp(Drivers::St7789& lcd,
|
||||||
Components::LittleVgl& lvgl,
|
Components::LittleVgl& lvgl,
|
||||||
@ -55,14 +56,14 @@ namespace Pinetime {
|
|||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::MotorController& motorController,
|
Pinetime::Controllers::MotorController& motorController,
|
||||||
Pinetime::Controllers::MotionController& motionController,
|
Pinetime::Controllers::MotionController& motionController,
|
||||||
Pinetime::Controllers::TimerController& timerController);
|
Pinetime::Controllers::TimerController& timerController,
|
||||||
|
Pinetime::Controllers::TouchHandler& touchHandler);
|
||||||
void Start();
|
void Start();
|
||||||
void PushMessage(Display::Messages msg);
|
void PushMessage(Display::Messages msg);
|
||||||
|
|
||||||
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||||
|
|
||||||
void SetFullRefresh(FullRefreshDirections direction);
|
void SetFullRefresh(FullRefreshDirections direction);
|
||||||
void SetTouchMode(TouchModes mode);
|
|
||||||
|
|
||||||
void Register(Pinetime::System::SystemTask* systemTask);
|
void Register(Pinetime::System::SystemTask* systemTask);
|
||||||
|
|
||||||
@ -81,6 +82,7 @@ namespace Pinetime {
|
|||||||
Pinetime::Controllers::MotorController& motorController;
|
Pinetime::Controllers::MotorController& motorController;
|
||||||
Pinetime::Controllers::MotionController& motionController;
|
Pinetime::Controllers::MotionController& motionController;
|
||||||
Pinetime::Controllers::TimerController& timerController;
|
Pinetime::Controllers::TimerController& timerController;
|
||||||
|
Pinetime::Controllers::TouchHandler& touchHandler;
|
||||||
|
|
||||||
Pinetime::Controllers::FirmwareValidator validator;
|
Pinetime::Controllers::FirmwareValidator validator;
|
||||||
Controllers::BrightnessController brightnessController;
|
Controllers::BrightnessController brightnessController;
|
||||||
@ -100,9 +102,7 @@ namespace Pinetime {
|
|||||||
FullRefreshDirections returnDirection = FullRefreshDirections::None;
|
FullRefreshDirections returnDirection = FullRefreshDirections::None;
|
||||||
TouchEvents returnTouchEvent = TouchEvents::None;
|
TouchEvents returnTouchEvent = TouchEvents::None;
|
||||||
|
|
||||||
TouchModes touchMode = TouchModes::Gestures;
|
TouchEvents GetGesture();
|
||||||
|
|
||||||
TouchEvents OnTouchEvent();
|
|
||||||
void RunningState();
|
void RunningState();
|
||||||
void IdleState();
|
void IdleState();
|
||||||
static void Process(void* instance);
|
static void Process(void* instance);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <task.h>
|
#include <task.h>
|
||||||
#include <libraries/log/nrf_log.h>
|
#include <libraries/log/nrf_log.h>
|
||||||
#include <components/rle/RleDecoder.h>
|
#include <components/rle/RleDecoder.h>
|
||||||
|
#include <touchhandler/TouchHandler.h>
|
||||||
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
||||||
|
|
||||||
using namespace Pinetime::Applications;
|
using namespace Pinetime::Applications;
|
||||||
@ -19,7 +20,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::MotorController& motorController,
|
Pinetime::Controllers::MotorController& motorController,
|
||||||
Pinetime::Controllers::MotionController& motionController,
|
Pinetime::Controllers::MotionController& motionController,
|
||||||
Pinetime::Controllers::TimerController& timerController)
|
Pinetime::Controllers::TimerController& timerController,
|
||||||
|
Pinetime::Controllers::TouchHandler& touchHandler)
|
||||||
: lcd {lcd}, bleController {bleController} {
|
: lcd {lcd}, bleController {bleController} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,9 @@ namespace Pinetime {
|
|||||||
namespace System {
|
namespace System {
|
||||||
class SystemTask;
|
class SystemTask;
|
||||||
};
|
};
|
||||||
|
namespace Controllers {
|
||||||
|
class TouchHandler;
|
||||||
|
}
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
class DisplayApp {
|
class DisplayApp {
|
||||||
public:
|
public:
|
||||||
@ -44,7 +47,8 @@ namespace Pinetime {
|
|||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Pinetime::Controllers::MotorController& motorController,
|
Pinetime::Controllers::MotorController& motorController,
|
||||||
Pinetime::Controllers::MotionController& motionController,
|
Pinetime::Controllers::MotionController& motionController,
|
||||||
Pinetime::Controllers::TimerController& timerController);
|
Pinetime::Controllers::TimerController& timerController,
|
||||||
|
Pinetime::Controllers::TouchHandler& touchHandler);
|
||||||
void Start();
|
void Start();
|
||||||
void PushMessage(Pinetime::Applications::Display::Messages msg);
|
void PushMessage(Pinetime::Applications::Display::Messages msg);
|
||||||
void Register(Pinetime::System::SystemTask* systemTask);
|
void Register(Pinetime::System::SystemTask* systemTask);
|
||||||
|
@ -32,6 +32,9 @@ namespace Pinetime {
|
|||||||
}
|
}
|
||||||
void SetNewTapEvent(uint16_t x, uint16_t y) {
|
void SetNewTapEvent(uint16_t x, uint16_t y) {
|
||||||
}
|
}
|
||||||
|
void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) {
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,43 +166,21 @@ void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
|||||||
lv_disp_flush_ready(&disp_drv);
|
lv_disp_flush_ready(&disp_drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) {
|
void LittleVgl::SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) {
|
||||||
tap_x = x;
|
tap_x = x;
|
||||||
tap_y = y;
|
tap_y = y;
|
||||||
tapped = true;
|
tapped = contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
|
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||||
|
ptr->point.x = tap_x;
|
||||||
|
ptr->point.y = tap_y;
|
||||||
if (tapped) {
|
if (tapped) {
|
||||||
ptr->point.x = tap_x;
|
|
||||||
ptr->point.y = tap_y;
|
|
||||||
ptr->state = LV_INDEV_STATE_PR;
|
ptr->state = LV_INDEV_STATE_PR;
|
||||||
tapped = false;
|
|
||||||
} else {
|
} else {
|
||||||
ptr->state = LV_INDEV_STATE_REL;
|
ptr->state = LV_INDEV_STATE_REL;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
/*
|
|
||||||
auto info = touchPanel.GetTouchInfo();
|
|
||||||
|
|
||||||
if((previousClick.x != info.x || previousClick.y != info.y) &&
|
|
||||||
(info.gesture == Drivers::Cst816S::Gestures::SingleTap)) {
|
|
||||||
// TODO For an unknown reason, the first touch is taken twice into account.
|
|
||||||
// 'firstTouch' is a quite'n'dirty workaound until I find a better solution
|
|
||||||
if(firstTouch) ptr->state = LV_INDEV_STATE_REL;
|
|
||||||
else ptr->state = LV_INDEV_STATE_PR;
|
|
||||||
firstTouch = false;
|
|
||||||
previousClick.x = info.x;
|
|
||||||
previousClick.y = info.y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ptr->state = LV_INDEV_STATE_REL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->point.x = info.x;
|
|
||||||
ptr->point.y = info.y;
|
|
||||||
return false;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::InitTheme() {
|
void LittleVgl::InitTheme() {
|
||||||
|
@ -24,7 +24,7 @@ namespace Pinetime {
|
|||||||
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
|
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
|
||||||
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
||||||
void SetFullRefresh(FullRefreshDirections direction);
|
void SetFullRefresh(FullRefreshDirections direction);
|
||||||
void SetNewTapEvent(uint16_t x, uint16_t y);
|
void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitDisplay();
|
void InitDisplay();
|
||||||
|
@ -13,7 +13,9 @@ namespace Pinetime {
|
|||||||
NewNotification,
|
NewNotification,
|
||||||
TimerDone,
|
TimerDone,
|
||||||
BleFirmwareUpdateStarted,
|
BleFirmwareUpdateStarted,
|
||||||
UpdateTimeOut
|
UpdateTimeOut,
|
||||||
|
DimScreen,
|
||||||
|
RestoreBrightness
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* Do not enable font compression and horizontal subpixel hinting
|
* Do not enable font compression and horizontal subpixel hinting
|
||||||
* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
||||||
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following
|
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following
|
||||||
range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569`
|
range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015`
|
||||||
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
|
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
|
||||||
* Add the font .c file path to src/CMakeLists.txt
|
* Add the font .c file path to src/CMakeLists.txt
|
||||||
* Add an LV_FONT_DECLARE line in src/libs/lv_conf.h
|
* Add an LV_FONT_DECLARE line in src/libs/lv_conf.h
|
||||||
|
@ -734,6 +734,15 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0xff, 0x7, 0xef, 0xf0, 0x10, 0xff, 0x0, 0x3,
|
0xff, 0x7, 0xef, 0xf0, 0x10, 0xff, 0x0, 0x3,
|
||||||
0xc0, 0x0,
|
0xc0, 0x0,
|
||||||
|
|
||||||
|
/* U+F015 "" */
|
||||||
|
0x0, 0x38, 0xe0, 0x0, 0xf9, 0xc0, 0x3, 0xfb,
|
||||||
|
0x80, 0x1e, 0x3f, 0x0, 0x79, 0x3e, 0x1, 0xe7,
|
||||||
|
0x3c, 0xf, 0x9f, 0xbc, 0x3c, 0xff, 0x9e, 0xf3,
|
||||||
|
0xff, 0x9e, 0xcf, 0xff, 0x98, 0x3f, 0xff, 0x80,
|
||||||
|
0x7f, 0xff, 0x0, 0xfc, 0x7e, 0x1, 0xf8, 0xfc,
|
||||||
|
0x3, 0xf1, 0xf8, 0x7, 0xe3, 0xf0, 0xf, 0xc7,
|
||||||
|
0xe0,
|
||||||
|
|
||||||
/* U+F017 "" */
|
/* U+F017 "" */
|
||||||
0x3, 0xf8, 0x1, 0xff, 0xc0, 0x7f, 0xfc, 0x1f,
|
0x3, 0xf8, 0x1, 0xff, 0xc0, 0x7f, 0xfc, 0x1f,
|
||||||
0xff, 0xc7, 0xf1, 0xfc, 0xfe, 0x3f, 0x9f, 0xc7,
|
0xff, 0xc7, 0xf1, 0xfc, 0xfe, 0x3f, 0x9f, 0xc7,
|
||||||
@ -823,6 +832,14 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0xdf, 0x9e, 0x38, 0xf3, 0x7, 0x6, 0x0, 0xe0,
|
0xdf, 0x9e, 0x38, 0xf3, 0x7, 0x6, 0x0, 0xe0,
|
||||||
0x0, 0x1c, 0x0, 0x3, 0x80, 0x0, 0x70, 0x0,
|
0x0, 0x1c, 0x0, 0x3, 0x80, 0x0, 0x70, 0x0,
|
||||||
|
|
||||||
|
/* U+F06E "" */
|
||||||
|
0x0, 0xfe, 0x0, 0xf, 0xff, 0x80, 0x3e, 0xf,
|
||||||
|
0x80, 0xf8, 0xf, 0x83, 0xe3, 0x8f, 0x8f, 0x87,
|
||||||
|
0x8f, 0xbf, 0x1f, 0x9f, 0xfe, 0xff, 0x3f, 0xfd,
|
||||||
|
0xfe, 0x7e, 0xf9, 0xf8, 0xf8, 0xf9, 0xe3, 0xe0,
|
||||||
|
0xf8, 0xf, 0x80, 0xf8, 0x3e, 0x0, 0xff, 0xf0,
|
||||||
|
0x0, 0x3f, 0x80, 0x0,
|
||||||
|
|
||||||
/* U+F095 "" */
|
/* U+F095 "" */
|
||||||
0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x7, 0xf0,
|
0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x7, 0xf0,
|
||||||
0x0, 0x7f, 0x0, 0x7, 0xf0, 0x0, 0xff, 0x0,
|
0x0, 0x7f, 0x0, 0x7, 0xf0, 0x0, 0xff, 0x0,
|
||||||
@ -861,6 +878,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x1, 0xf8, 0x0, 0x9f, 0xc0, 0xf, 0xfc, 0x0,
|
0x1, 0xf8, 0x0, 0x9f, 0xc0, 0xf, 0xfc, 0x0,
|
||||||
0x7f, 0xc0, 0x7, 0xf8, 0x0, 0x1f, 0x0, 0x0,
|
0x7f, 0xc0, 0x7, 0xf8, 0x0, 0x1f, 0x0, 0x0,
|
||||||
|
|
||||||
|
/* U+F201 "" */
|
||||||
|
0x40, 0x0, 0x7, 0x0, 0x0, 0x38, 0x1, 0xf9,
|
||||||
|
0xc0, 0x7, 0xce, 0x18, 0x1e, 0x71, 0xe1, 0xf3,
|
||||||
|
0x9f, 0x9d, 0x9d, 0xff, 0xc4, 0xe6, 0x7c, 0x7,
|
||||||
|
0x1, 0xc0, 0x38, 0x0, 0x1, 0xc0, 0x0, 0xe,
|
||||||
|
0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xe0,
|
||||||
|
|
||||||
/* U+F21E "" */
|
/* U+F21E "" */
|
||||||
0x1e, 0x7, 0x83, 0xf9, 0xfe, 0x7f, 0xff, 0xef,
|
0x1e, 0x7, 0x83, 0xf9, 0xfe, 0x7f, 0xff, 0xef,
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xfc,
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xfc,
|
||||||
@ -1182,42 +1206,45 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
{.bitmap_index = 2484, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 2484, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 2498, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 2498, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 2511, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 2511, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 2561, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 2561, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 2609, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 2610, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 2659, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 2658, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 2688, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 2708, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 2743, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 2737, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 2782, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 2792, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 2825, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
{.bitmap_index = 2831, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 2853, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 2874, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
||||||
{.bitmap_index = 2901, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 2902, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 2940, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 2950, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 2979, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
{.bitmap_index = 2989, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 3007, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3028, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1},
|
||||||
{.bitmap_index = 3055, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3056, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 3108, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3104, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 3127, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3148, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 3177, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3201, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 3213, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3220, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 3261, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 3270, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 3304, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 3306, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 3342, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 3354, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 3380, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 3394, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 3418, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 3437, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 3456, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 3475, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 3494, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3513, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 3530, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
|
{.bitmap_index = 3551, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 3568, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3589, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 3597, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 3627, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 3635, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3663, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
|
||||||
{.bitmap_index = 3701, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 3701, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 3750, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3730, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 3800, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3768, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 3860, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3834, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 3913, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 3883, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 3974, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3933, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 4029, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 3993, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 4082, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0}
|
{.bitmap_index = 4046, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 4107, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 4162, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 4215, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
@ -1225,11 +1252,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
*--------------------*/
|
*--------------------*/
|
||||||
|
|
||||||
static const uint16_t unicode_list_2[] = {
|
static const uint16_t unicode_list_2[] = {
|
||||||
0x0, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39, 0x47,
|
0x0, 0x14, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39,
|
||||||
0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x94, 0x128, 0x184,
|
0x47, 0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x6d, 0x94,
|
||||||
0x1e5, 0x1fb, 0x21d, 0x23f, 0x240, 0x241, 0x242, 0x243,
|
0x128, 0x184, 0x1e5, 0x1fb, 0x200, 0x21d, 0x23f, 0x240,
|
||||||
0x251, 0x292, 0x293, 0x2f1, 0x3dc, 0x3fc, 0x45c, 0x54a,
|
0x241, 0x242, 0x243, 0x251, 0x292, 0x293, 0x2f1, 0x3dc,
|
||||||
0x55f, 0x568, 0x59e, 0x59f, 0x6a8
|
0x3fc, 0x45c, 0x54a, 0x55f, 0x568, 0x59e, 0x59f, 0x6a8
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Collect the unicode lists and glyph_id offsets*/
|
/*Collect the unicode lists and glyph_id offsets*/
|
||||||
@ -1245,7 +1272,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.range_start = 61441, .range_length = 1705, .glyph_id_start = 160,
|
.range_start = 61441, .range_length = 1705, .glyph_id_start = 160,
|
||||||
.unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 37, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
.unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 40, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,12 +34,6 @@ ApplicationList::~ApplicationList() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApplicationList::Refresh() {
|
|
||||||
if (running)
|
|
||||||
running = screens.Refresh();
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
return screens.OnTouchEvent(event);
|
return screens.OnTouchEvent(event);
|
||||||
}
|
}
|
||||||
@ -62,7 +56,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
|||||||
{Symbols::paintbrush, Apps::Paint},
|
{Symbols::paintbrush, Apps::Paint},
|
||||||
{Symbols::paddle, Apps::Paddle},
|
{Symbols::paddle, Apps::Paddle},
|
||||||
{"2", Apps::Twos},
|
{"2", Apps::Twos},
|
||||||
{"M", Apps::Motion},
|
{Symbols::chartLine, Apps::Motion},
|
||||||
{Symbols::drum, Apps::Metronome},
|
{Symbols::drum, Apps::Metronome},
|
||||||
{"", Apps::None},
|
{"", Apps::None},
|
||||||
}};
|
}};
|
||||||
|
@ -18,7 +18,6 @@ namespace Pinetime {
|
|||||||
Pinetime::Controllers::Battery& batteryController,
|
Pinetime::Controllers::Battery& batteryController,
|
||||||
Controllers::DateTime& dateTimeController);
|
Controllers::DateTime& dateTimeController);
|
||||||
~ApplicationList() override;
|
~ApplicationList() override;
|
||||||
bool Refresh() override;
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) {
|
const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) {
|
||||||
if (batteryPercent > 90)
|
if (batteryPercent > 87)
|
||||||
return Symbols::batteryFull;
|
return Symbols::batteryFull;
|
||||||
if (batteryPercent > 75)
|
if (batteryPercent > 62)
|
||||||
return Symbols::batteryThreeQuarter;
|
return Symbols::batteryThreeQuarter;
|
||||||
if (batteryPercent > 50)
|
if (batteryPercent > 37)
|
||||||
return Symbols::batteryHalf;
|
return Symbols::batteryHalf;
|
||||||
if (batteryPercent > 25)
|
if (batteryPercent > 12)
|
||||||
return Symbols::batteryOneQuarter;
|
return Symbols::batteryOneQuarter;
|
||||||
return Symbols::batteryEmpty;
|
return Symbols::batteryEmpty;
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,6 @@
|
|||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
static void lv_update_task(struct _lv_task_t* task) {
|
|
||||||
auto user_data = static_cast<BatteryInfo*>(task->user_data);
|
|
||||||
user_data->UpdateScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
|
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
|
||||||
: Screen(app), batteryController {batteryController} {
|
: Screen(app), batteryController {batteryController} {
|
||||||
|
|
||||||
@ -49,16 +44,16 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
|
|||||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||||
lv_label_set_text_static(backgroundLabel, "");
|
lv_label_set_text_static(backgroundLabel, "");
|
||||||
|
|
||||||
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this);
|
taskRefresh = lv_task_create(RefreshTaskCallback, 5000, LV_TASK_PRIO_MID, this);
|
||||||
UpdateScreen();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
BatteryInfo::~BatteryInfo() {
|
BatteryInfo::~BatteryInfo() {
|
||||||
lv_task_del(taskUpdate);
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatteryInfo::UpdateScreen() {
|
void BatteryInfo::Refresh() {
|
||||||
|
|
||||||
batteryController.Update();
|
batteryController.Update();
|
||||||
|
|
||||||
@ -85,7 +80,3 @@ void BatteryInfo::UpdateScreen() {
|
|||||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
|
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
|
||||||
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
|
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BatteryInfo::Refresh() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
@ -19,9 +19,7 @@ namespace Pinetime {
|
|||||||
BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController);
|
BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController);
|
||||||
~BatteryInfo() override;
|
~BatteryInfo() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
void UpdateScreen();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::Controllers::Battery& batteryController;
|
Pinetime::Controllers::Battery& batteryController;
|
||||||
@ -31,7 +29,7 @@ namespace Pinetime {
|
|||||||
lv_obj_t* charging_bar;
|
lv_obj_t* charging_bar;
|
||||||
lv_obj_t* status;
|
lv_obj_t* status;
|
||||||
|
|
||||||
lv_task_t* taskUpdate;
|
lv_task_t* taskRefresh;
|
||||||
|
|
||||||
uint8_t batteryPercent = 0;
|
uint8_t batteryPercent = 0;
|
||||||
uint16_t batteryVoltage = 0;
|
uint16_t batteryVoltage = 0;
|
||||||
|
@ -30,10 +30,6 @@ Brightness::~Brightness() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Brightness::Refresh() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
|
const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case Pinetime::Controllers::BrightnessController::Levels::Off:
|
case Pinetime::Controllers::BrightnessController::Levels::Off:
|
||||||
|
@ -12,7 +12,6 @@ namespace Pinetime {
|
|||||||
public:
|
public:
|
||||||
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
|
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
|
||||||
~Brightness() override;
|
~Brightness() override;
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
|
|
||||||
|
@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
#include <date/date.h>
|
#include <date/date.h>
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
#include <cstdio>
|
|
||||||
#include "BatteryIcon.h"
|
|
||||||
#include "BleIcon.h"
|
|
||||||
#include "NotificationIcon.h"
|
|
||||||
#include "Symbols.h"
|
|
||||||
#include "components/battery/BatteryController.h"
|
#include "components/battery/BatteryController.h"
|
||||||
#include "components/motion/MotionController.h"
|
#include "components/motion/MotionController.h"
|
||||||
#include "components/ble/BleController.h"
|
#include "components/ble/BleController.h"
|
||||||
@ -55,11 +50,6 @@ Clock::~Clock() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Clock::Refresh() {
|
|
||||||
screen->Refresh();
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
return screen->OnTouchEvent(event);
|
return screen->OnTouchEvent(event);
|
||||||
}
|
}
|
||||||
@ -89,16 +79,3 @@ std::unique_ptr<Screen> Clock::PineTimeStyleScreen() {
|
|||||||
settingsController,
|
settingsController,
|
||||||
motionController);
|
motionController);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Examples for more watch faces
|
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
|
|
||||||
return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager,
|
|
||||||
settingsController);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() {
|
|
||||||
return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager,
|
|
||||||
settingsController);
|
|
||||||
}
|
|
||||||
*/
|
|
@ -9,9 +9,6 @@
|
|||||||
#include "components/datetime/DateTimeController.h"
|
#include "components/datetime/DateTimeController.h"
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Drivers {
|
|
||||||
class BMA421;
|
|
||||||
}
|
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
class Settings;
|
class Settings;
|
||||||
class Battery;
|
class Battery;
|
||||||
@ -34,8 +31,6 @@ namespace Pinetime {
|
|||||||
Controllers::MotionController& motionController);
|
Controllers::MotionController& motionController);
|
||||||
~Clock() override;
|
~Clock() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -51,10 +46,6 @@ namespace Pinetime {
|
|||||||
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
||||||
std::unique_ptr<Screen> WatchFaceAnalogScreen();
|
std::unique_ptr<Screen> WatchFaceAnalogScreen();
|
||||||
std::unique_ptr<Screen> PineTimeStyleScreen();
|
std::unique_ptr<Screen> PineTimeStyleScreen();
|
||||||
|
|
||||||
// Examples for more watch faces
|
|
||||||
// std::unique_ptr<Screen> WatchFaceMinimalScreen();
|
|
||||||
// std::unique_ptr<Screen> WatchFaceCustomScreen();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,16 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime
|
|||||||
lv_label_set_text(percentLabel, "Waiting...");
|
lv_label_set_text(percentLabel, "Waiting...");
|
||||||
lv_obj_set_auto_realign(percentLabel, true);
|
lv_obj_set_auto_realign(percentLabel, true);
|
||||||
lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60);
|
lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60);
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
startTime = xTaskGetTickCount();
|
startTime = xTaskGetTickCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
FirmwareUpdate::~FirmwareUpdate() {
|
FirmwareUpdate::~FirmwareUpdate() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FirmwareUpdate::Refresh() {
|
void FirmwareUpdate::Refresh() {
|
||||||
switch (bleController.State()) {
|
switch (bleController.State()) {
|
||||||
default:
|
default:
|
||||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
|
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
|
||||||
@ -73,7 +75,6 @@ bool FirmwareUpdate::Refresh() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirmwareUpdate::DisplayProgression() const {
|
void FirmwareUpdate::DisplayProgression() const {
|
||||||
|
@ -16,7 +16,7 @@ namespace Pinetime {
|
|||||||
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
|
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
|
||||||
~FirmwareUpdate() override;
|
~FirmwareUpdate() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class States { Idle, Running, Validated, Error };
|
enum class States { Idle, Running, Validated, Error };
|
||||||
@ -36,6 +36,7 @@ namespace Pinetime {
|
|||||||
|
|
||||||
void UpdateError();
|
void UpdateError();
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
TickType_t startTime;
|
TickType_t startTime;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,9 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app,
|
|||||||
lv_label_set_text(labelIsValidated, "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
|
lv_label_set_text(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 = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
|
||||||
buttonValidate->user_data = this;
|
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_set_event_cb(buttonValidate, ButtonEventHandler);
|
lv_obj_set_event_cb(buttonValidate, ButtonEventHandler);
|
||||||
lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x009900));
|
lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x009900));
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app,
|
|||||||
|
|
||||||
buttonReset = lv_btn_create(lv_scr_act(), nullptr);
|
buttonReset = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
buttonReset->user_data = this;
|
buttonReset->user_data = this;
|
||||||
|
lv_obj_set_size(buttonReset, 115, 50);
|
||||||
lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x990000));
|
lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x990000));
|
||||||
lv_obj_set_event_cb(buttonReset, ButtonEventHandler);
|
lv_obj_set_event_cb(buttonReset, ButtonEventHandler);
|
||||||
@ -61,15 +63,11 @@ FirmwareValidation::~FirmwareValidation() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FirmwareValidation::Refresh() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
||||||
if (object == buttonValidate && event == LV_EVENT_PRESSED) {
|
if (object == buttonValidate && event == LV_EVENT_CLICKED) {
|
||||||
validator.Validate();
|
validator.Validate();
|
||||||
running = false;
|
running = false;
|
||||||
} else if (object == buttonReset && event == LV_EVENT_PRESSED) {
|
} else if (object == buttonReset && event == LV_EVENT_CLICKED) {
|
||||||
validator.Reset();
|
validator.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@ namespace Pinetime {
|
|||||||
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
|
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
|
||||||
~FirmwareValidation() override;
|
~FirmwareValidation() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -65,10 +65,6 @@ void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlashLight::Refresh() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@ namespace Pinetime {
|
|||||||
FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness);
|
FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness);
|
||||||
~FlashLight() override;
|
~FlashLight() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||||
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
|
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
|
||||||
|
|
||||||
|
@ -64,14 +64,17 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
|
|||||||
UpdateStartStopButton(isHrRunning);
|
UpdateStartStopButton(isHrRunning);
|
||||||
if (isHrRunning)
|
if (isHrRunning)
|
||||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeartRate::~HeartRate() {
|
HeartRate::~HeartRate() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeartRate::Refresh() {
|
void HeartRate::Refresh() {
|
||||||
|
|
||||||
auto state = heartRateController.State();
|
auto state = heartRateController.State();
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -86,8 +89,6 @@ bool HeartRate::Refresh() {
|
|||||||
|
|
||||||
lv_label_set_text(label_status, ToString(state));
|
lv_label_set_text(label_status, ToString(state));
|
||||||
lv_obj_align(label_status, label_hr, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
lv_obj_align(label_status, label_hr, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRate::OnStartStopEvent(lv_event_t event) {
|
void HeartRate::OnStartStopEvent(lv_event_t event) {
|
||||||
|
@ -20,7 +20,7 @@ namespace Pinetime {
|
|||||||
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask);
|
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask);
|
||||||
~HeartRate() override;
|
~HeartRate() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
void OnStartStopEvent(lv_event_t event);
|
void OnStartStopEvent(lv_event_t event);
|
||||||
|
|
||||||
@ -33,6 +33,8 @@ namespace Pinetime {
|
|||||||
lv_obj_t* label_status;
|
lv_obj_t* label_status;
|
||||||
lv_obj_t* btn_startStop;
|
lv_obj_t* btn_startStop;
|
||||||
lv_obj_t* label_startStop;
|
lv_obj_t* label_startStop;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,13 @@
|
|||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
|
||||||
std::fill(b, b + bufferSize, selectColor);
|
std::fill(b, b + bufferSize, selectColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiniPaint::~InfiniPaint() {
|
InfiniPaint::~InfiniPaint() {
|
||||||
// Reset the touchmode
|
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InfiniPaint::Refresh() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case Pinetime::Applications::TouchEvents::LongTap:
|
case Pinetime::Applications::TouchEvents::LongTap:
|
||||||
|
@ -17,8 +17,6 @@ namespace Pinetime {
|
|||||||
|
|
||||||
~InfiniPaint() override;
|
~InfiniPaint() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
|
|
||||||
bool OnTouchEvent(uint16_t x, uint16_t y) override;
|
bool OnTouchEvent(uint16_t x, uint16_t y) override;
|
||||||
|
@ -6,10 +6,10 @@ Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::Displ
|
|||||||
: Screen(app), labelText {labelText} {
|
: Screen(app), labelText {labelText} {
|
||||||
|
|
||||||
if (numScreens > 1) {
|
if (numScreens > 1) {
|
||||||
pageIndicatorBasePoints[0].x = 240 - 1;
|
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorBasePoints[0].y = 6;
|
pageIndicatorBasePoints[0].y = 0;
|
||||||
pageIndicatorBasePoints[1].x = 240 - 1;
|
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorBasePoints[1].y = 240 - 6;
|
pageIndicatorBasePoints[1].y = LV_VER_RES;
|
||||||
|
|
||||||
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
|
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
|
||||||
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||||
@ -17,13 +17,13 @@ Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::Displ
|
|||||||
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||||
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
||||||
|
|
||||||
uint16_t indicatorSize = 228 / numScreens;
|
uint16_t indicatorSize = LV_VER_RES / numScreens;
|
||||||
uint16_t indicatorPos = indicatorSize * screenID;
|
uint16_t indicatorPos = indicatorSize * screenID;
|
||||||
|
|
||||||
pageIndicatorPoints[0].x = 240 - 1;
|
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorPoints[0].y = (6 + indicatorPos);
|
pageIndicatorPoints[0].y = indicatorPos;
|
||||||
pageIndicatorPoints[1].x = 240 - 1;
|
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorPoints[1].y = (6 + indicatorPos) + indicatorSize;
|
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
|
||||||
|
|
||||||
pageIndicator = lv_line_create(lv_scr_act(), NULL);
|
pageIndicator = lv_line_create(lv_scr_act(), NULL);
|
||||||
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||||
@ -36,7 +36,3 @@ Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::Displ
|
|||||||
Label::~Label() {
|
Label::~Label() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Label::Refresh() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
@ -12,11 +12,7 @@ namespace Pinetime {
|
|||||||
Label(uint8_t screenID, uint8_t numScreens, DisplayApp* app, lv_obj_t* labelText);
|
Label(uint8_t screenID, uint8_t numScreens, DisplayApp* app, lv_obj_t* labelText);
|
||||||
~Label() override;
|
~Label() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool running = true;
|
|
||||||
|
|
||||||
lv_obj_t* labelText = nullptr;
|
lv_obj_t* labelText = nullptr;
|
||||||
lv_point_t pageIndicatorBasePoints[2];
|
lv_point_t pageIndicatorBasePoints[2];
|
||||||
lv_point_t pageIndicatorPoints[2];
|
lv_point_t pageIndicatorPoints[2];
|
||||||
|
@ -25,42 +25,38 @@ List::List(uint8_t screenID,
|
|||||||
settingsController.SetSettingsMenu(screenID);
|
settingsController.SetSettingsMenu(screenID);
|
||||||
|
|
||||||
if (numScreens > 1) {
|
if (numScreens > 1) {
|
||||||
pageIndicatorBasePoints[0].x = 240 - 1;
|
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorBasePoints[0].y = 6;
|
pageIndicatorBasePoints[0].y = 0;
|
||||||
pageIndicatorBasePoints[1].x = 240 - 1;
|
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorBasePoints[1].y = 240 - 6;
|
pageIndicatorBasePoints[1].y = LV_VER_RES;
|
||||||
|
|
||||||
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
|
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
|
||||||
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||||
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
||||||
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
|
||||||
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
||||||
|
|
||||||
uint16_t indicatorSize = 228 / numScreens;
|
const uint16_t indicatorSize = LV_VER_RES / numScreens;
|
||||||
uint16_t indicatorPos = indicatorSize * screenID;
|
const uint16_t indicatorPos = indicatorSize * screenID;
|
||||||
|
|
||||||
pageIndicatorPoints[0].x = 240 - 1;
|
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorPoints[0].y = 6 + indicatorPos;
|
pageIndicatorPoints[0].y = indicatorPos;
|
||||||
pageIndicatorPoints[1].x = 240 - 1;
|
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
|
||||||
pageIndicatorPoints[1].y = 6 + indicatorPos + indicatorSize;
|
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
|
||||||
|
|
||||||
pageIndicator = lv_line_create(lv_scr_act(), NULL);
|
pageIndicator = lv_line_create(lv_scr_act(), NULL);
|
||||||
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||||
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||||
lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
|
||||||
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
// lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
|
||||||
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
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, 4);
|
||||||
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_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
|
||||||
lv_obj_set_pos(container1, 0, 0);
|
lv_obj_set_pos(container1, 0, 0);
|
||||||
lv_obj_set_width(container1, LV_HOR_RES - 15);
|
lv_obj_set_width(container1, LV_HOR_RES - 8);
|
||||||
lv_obj_set_height(container1, LV_VER_RES);
|
lv_obj_set_height(container1, LV_VER_RES);
|
||||||
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
|
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
|
||||||
|
|
||||||
@ -73,11 +69,11 @@ List::List(uint8_t screenID,
|
|||||||
|
|
||||||
itemApps[i] = lv_btn_create(container1, nullptr);
|
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_20);
|
lv_obj_set_style_local_bg_opa(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
||||||
lv_obj_set_style_local_radius(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
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);
|
lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
||||||
|
|
||||||
lv_obj_set_width(itemApps[i], LV_HOR_RES - 25);
|
lv_obj_set_width(itemApps[i], LV_HOR_RES - 8);
|
||||||
lv_obj_set_height(itemApps[i], 52);
|
lv_obj_set_height(itemApps[i], 57);
|
||||||
lv_obj_set_event_cb(itemApps[i], ButtonEventHandler);
|
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_ROW_MID);
|
||||||
itemApps[i]->user_data = this;
|
itemApps[i]->user_data = this;
|
||||||
@ -102,13 +98,8 @@ List::~List() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool List::Refresh() {
|
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void List::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
void List::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
||||||
if (event == LV_EVENT_RELEASED) {
|
if (event == LV_EVENT_CLICKED) {
|
||||||
for (int i = 0; i < MAXLISTITEMS; i++) {
|
for (int i = 0; i < MAXLISTITEMS; i++) {
|
||||||
if (apps[i] != Apps::None && object == itemApps[i]) {
|
if (apps[i] != Apps::None && object == itemApps[i]) {
|
||||||
app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Up);
|
app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Up);
|
||||||
|
@ -27,8 +27,6 @@ namespace Pinetime {
|
|||||||
std::array<Applications, MAXLISTITEMS>& applications);
|
std::array<Applications, MAXLISTITEMS>& applications);
|
||||||
~List() override;
|
~List() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
|
||||||
|
|
||||||
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -20,17 +20,17 @@ Meter::Meter(Pinetime::Applications::DisplayApp* app) : Screen(app) {
|
|||||||
|
|
||||||
lv_obj_set_size(lmeter, 200, 200);
|
lv_obj_set_size(lmeter, 200, 200);
|
||||||
lv_obj_align(lmeter, nullptr, LV_ALIGN_CENTER, 0, 0);
|
lv_obj_align(lmeter, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Meter::~Meter() {
|
Meter::~Meter() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Meter::Refresh() {
|
void Meter::Refresh() {
|
||||||
lv_linemeter_set_value(lmeter, value++); /*Set the current value*/
|
lv_linemeter_set_value(lmeter, value++); /*Set the current value*/
|
||||||
if (value >= 60)
|
if (value >= 60)
|
||||||
value = 0;
|
value = 0;
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,15 @@ namespace Pinetime {
|
|||||||
Meter(DisplayApp* app);
|
Meter(DisplayApp* app);
|
||||||
~Meter() override;
|
~Meter() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lv_style_t style_lmeter;
|
lv_style_t style_lmeter;
|
||||||
lv_obj_t* lmeter;
|
lv_obj_t* lmeter;
|
||||||
|
|
||||||
uint32_t value = 0;
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,15 @@
|
|||||||
#include "Metronome.h"
|
#include "Metronome.h"
|
||||||
|
|
||||||
#include "Screen.h"
|
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "lvgl/lvgl.h"
|
|
||||||
#include "FreeRTOSConfig.h"
|
|
||||||
#include "task.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
float calculateDelta(const TickType_t startTime, const TickType_t currentTime) {
|
void eventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||||
TickType_t delta = 0;
|
auto* screen = static_cast<Metronome*>(obj->user_data);
|
||||||
// Take care of overflow
|
|
||||||
if (startTime > currentTime) {
|
|
||||||
delta = 0xffffffff - startTime;
|
|
||||||
delta += (currentTime + 1);
|
|
||||||
} else {
|
|
||||||
delta = currentTime - startTime;
|
|
||||||
}
|
|
||||||
return static_cast<float>(delta) / static_cast<float>(configTICK_RATE_HZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eventHandler(lv_obj_t* obj, lv_event_t event) {
|
|
||||||
Metronome* screen = static_cast<Metronome*>(obj->user_data);
|
|
||||||
screen->OnEvent(obj, event);
|
screen->OnEvent(obj, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x = 0, uint8_t y = 0) {
|
lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x, uint8_t y) {
|
||||||
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
|
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
|
||||||
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||||
@ -41,7 +21,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask)
|
Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask)
|
||||||
: Screen(app), running {true}, currentState {States::Stopped}, startTime {}, motorController {motorController}, systemTask {systemTask} {
|
: Screen(app), motorController {motorController}, systemTask {systemTask} {
|
||||||
|
|
||||||
bpmArc = lv_arc_create(lv_scr_act(), nullptr);
|
bpmArc = lv_arc_create(lv_scr_act(), nullptr);
|
||||||
bpmArc->user_data = this;
|
bpmArc->user_data = this;
|
||||||
@ -52,10 +32,10 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl
|
|||||||
lv_arc_set_value(bpmArc, bpm);
|
lv_arc_set_value(bpmArc, bpm);
|
||||||
lv_obj_set_size(bpmArc, 210, 210);
|
lv_obj_set_size(bpmArc, 210, 210);
|
||||||
lv_arc_set_adjustable(bpmArc, true);
|
lv_arc_set_adjustable(bpmArc, true);
|
||||||
lv_obj_align(bpmArc, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 7);
|
lv_obj_align(bpmArc, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||||
|
|
||||||
bpmValue = createLabel(std::to_string(lv_arc_get_value(bpmArc)).c_str(), bpmArc, LV_ALIGN_IN_TOP_MID, &jetbrains_mono_76, 0, 55);
|
bpmValue = createLabel("120", bpmArc, LV_ALIGN_IN_TOP_MID, &jetbrains_mono_76, 0, 55);
|
||||||
bpmLegend = createLabel("bpm", bpmValue, LV_ALIGN_OUT_BOTTOM_MID, &jetbrains_mono_bold_20, 0, 0);
|
createLabel("bpm", bpmValue, LV_ALIGN_OUT_BOTTOM_MID, &jetbrains_mono_bold_20, 0, 0);
|
||||||
|
|
||||||
bpmTap = lv_btn_create(lv_scr_act(), nullptr);
|
bpmTap = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
bpmTap->user_data = this;
|
bpmTap->user_data = this;
|
||||||
@ -69,55 +49,46 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl
|
|||||||
lv_obj_set_event_cb(bpbDropdown, eventHandler);
|
lv_obj_set_event_cb(bpbDropdown, eventHandler);
|
||||||
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
||||||
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_LIST, LV_STATE_DEFAULT, 20);
|
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_LIST, LV_STATE_DEFAULT, 20);
|
||||||
lv_obj_align(bpbDropdown, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 15, -4);
|
lv_obj_set_size(bpbDropdown, 115, 50);
|
||||||
|
lv_obj_align(bpbDropdown, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
lv_dropdown_set_options(bpbDropdown, "1\n2\n3\n4\n5\n6\n7\n8\n9");
|
lv_dropdown_set_options(bpbDropdown, "1\n2\n3\n4\n5\n6\n7\n8\n9");
|
||||||
lv_dropdown_set_selected(bpbDropdown, bpb - 1);
|
lv_dropdown_set_selected(bpbDropdown, bpb - 1);
|
||||||
bpbLegend = lv_label_create(bpbDropdown, nullptr);
|
lv_dropdown_set_show_selected(bpbDropdown, false);
|
||||||
lv_label_set_text(bpbLegend, "bpb");
|
lv_dropdown_set_text(bpbDropdown, "");
|
||||||
lv_obj_align(bpbLegend, bpbDropdown, LV_ALIGN_IN_RIGHT_MID, -15, 0);
|
|
||||||
|
currentBpbText = lv_label_create(bpbDropdown, nullptr);
|
||||||
|
lv_label_set_text_fmt(currentBpbText, "%d bpb", bpb);
|
||||||
|
lv_obj_align(currentBpbText, bpbDropdown, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
playPause = lv_btn_create(lv_scr_act(), nullptr);
|
playPause = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
playPause->user_data = this;
|
playPause->user_data = this;
|
||||||
lv_obj_set_event_cb(playPause, eventHandler);
|
lv_obj_set_event_cb(playPause, eventHandler);
|
||||||
lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10);
|
lv_obj_set_size(playPause, 115, 50);
|
||||||
lv_obj_set_height(playPause, 39);
|
lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
playPauseLabel = lv_label_create(playPause, nullptr);
|
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play);
|
||||||
lv_label_set_text(playPauseLabel, Symbols::play);
|
|
||||||
|
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Metronome::~Metronome() {
|
Metronome::~Metronome() {
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
lv_task_del(taskRefresh);
|
||||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Metronome::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
void Metronome::Refresh() {
|
||||||
return true;
|
if (metronomeStarted) {
|
||||||
}
|
if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) {
|
||||||
|
startTime += 60 * configTICK_RATE_HZ / bpm;
|
||||||
bool Metronome::Refresh() {
|
counter--;
|
||||||
switch (currentState) {
|
if (counter == 0) {
|
||||||
case States::Stopped: {
|
counter = bpb;
|
||||||
break;
|
motorController.RunForDuration(90);
|
||||||
}
|
} else {
|
||||||
case States::Running: {
|
motorController.RunForDuration(30);
|
||||||
if (calculateDelta(startTime, xTaskGetTickCount()) >= (60.0 / bpm)) {
|
|
||||||
counter--;
|
|
||||||
startTime -= 60.0 / bpm;
|
|
||||||
startTime = xTaskGetTickCount();
|
|
||||||
if (counter == 0) {
|
|
||||||
counter = bpb;
|
|
||||||
motorController.SetDuration(90);
|
|
||||||
} else {
|
|
||||||
motorController.SetDuration(30);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
|
void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
|
||||||
@ -128,42 +99,39 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
|
|||||||
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
|
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
|
||||||
} else if (obj == bpbDropdown) {
|
} else if (obj == bpbDropdown) {
|
||||||
bpb = lv_dropdown_get_selected(obj) + 1;
|
bpb = lv_dropdown_get_selected(obj) + 1;
|
||||||
|
lv_label_set_text_fmt(currentBpbText, "%d bpb", bpb);
|
||||||
|
lv_obj_realign(currentBpbText);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LV_EVENT_PRESSED: {
|
case LV_EVENT_PRESSED: {
|
||||||
if (obj == bpmTap) {
|
if (obj == bpmTap) {
|
||||||
float timeDelta = calculateDelta(tappedTime, xTaskGetTickCount());
|
TickType_t delta = xTaskGetTickCount() - tappedTime;
|
||||||
if (tappedTime == 0 || timeDelta > 3) {
|
if (tappedTime != 0 && delta < configTICK_RATE_HZ * 3) {
|
||||||
tappedTime = xTaskGetTickCount();
|
bpm = configTICK_RATE_HZ * 60 / delta;
|
||||||
} else {
|
|
||||||
bpm = ceil(60.0 / timeDelta);
|
|
||||||
lv_arc_set_value(bpmArc, bpm);
|
lv_arc_set_value(bpmArc, bpm);
|
||||||
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
|
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
|
||||||
tappedTime = xTaskGetTickCount();
|
|
||||||
}
|
}
|
||||||
|
tappedTime = xTaskGetTickCount();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LV_EVENT_CLICKED: {
|
case LV_EVENT_CLICKED: {
|
||||||
if (obj == playPause) {
|
if (obj == playPause) {
|
||||||
currentState = (currentState == States::Stopped ? States::Running : States::Stopped);
|
metronomeStarted = !metronomeStarted;
|
||||||
switch (currentState) {
|
if (metronomeStarted) {
|
||||||
case States::Stopped: {
|
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::pause);
|
||||||
lv_label_set_text(playPauseLabel, Symbols::play);
|
systemTask.PushMessage(System::Messages::DisableSleeping);
|
||||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
startTime = xTaskGetTickCount();
|
||||||
break;
|
counter = 1;
|
||||||
}
|
} else {
|
||||||
case States::Running: {
|
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play);
|
||||||
lv_label_set_text(playPauseLabel, Symbols::pause);
|
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||||
systemTask.PushMessage(System::Messages::DisableSleeping);
|
|
||||||
startTime = xTaskGetTickCount();
|
|
||||||
counter = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,32 +3,34 @@
|
|||||||
#include "systemtask/SystemTask.h"
|
#include "systemtask/SystemTask.h"
|
||||||
#include "components/motor/MotorController.h"
|
#include "components/motor/MotorController.h"
|
||||||
|
|
||||||
#include <array>
|
namespace Pinetime {
|
||||||
|
namespace Applications {
|
||||||
|
namespace Screens {
|
||||||
|
|
||||||
namespace Pinetime::Applications::Screens {
|
class Metronome : public Screen {
|
||||||
|
public:
|
||||||
|
Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask);
|
||||||
|
~Metronome() override;
|
||||||
|
void Refresh() override;
|
||||||
|
void OnEvent(lv_obj_t* obj, lv_event_t event);
|
||||||
|
|
||||||
class Metronome : public Screen {
|
private:
|
||||||
public:
|
TickType_t startTime = 0;
|
||||||
Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask);
|
TickType_t tappedTime = 0;
|
||||||
~Metronome() override;
|
Controllers::MotorController& motorController;
|
||||||
bool Refresh() override;
|
System::SystemTask& systemTask;
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
int16_t bpm = 120;
|
||||||
void OnEvent(lv_obj_t* obj, lv_event_t event);
|
uint8_t bpb = 4;
|
||||||
enum class States { Running, Stopped };
|
uint8_t counter = 1;
|
||||||
|
|
||||||
private:
|
bool metronomeStarted = false;
|
||||||
bool running;
|
|
||||||
States currentState;
|
|
||||||
TickType_t startTime;
|
|
||||||
TickType_t tappedTime = 0;
|
|
||||||
Controllers::MotorController& motorController;
|
|
||||||
System::SystemTask& systemTask;
|
|
||||||
uint16_t bpm = 120;
|
|
||||||
uint8_t bpb = 4;
|
|
||||||
uint8_t counter = 1;
|
|
||||||
|
|
||||||
lv_obj_t *bpmArc, *bpmTap, *bpmValue, *bpmLegend;
|
lv_obj_t *bpmArc, *bpmTap, *bpmValue;
|
||||||
lv_obj_t *bpbDropdown, *bpbLegend;
|
lv_obj_t *bpbDropdown, *currentBpbText;
|
||||||
lv_obj_t *playPause, *playPauseLabel;
|
lv_obj_t *playPause;
|
||||||
};
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,26 +37,25 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr
|
|||||||
lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
lv_label_set_text(labelStep, "Steps ---");
|
lv_label_set_text(labelStep, "Steps ---");
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Motion::~Motion() {
|
Motion::~Motion() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Motion::Refresh() {
|
void Motion::Refresh() {
|
||||||
lv_chart_set_next(chart, ser1, motionController.X());
|
lv_chart_set_next(chart, ser1, motionController.X());
|
||||||
lv_chart_set_next(chart, ser2, motionController.Y());
|
lv_chart_set_next(chart, ser2, motionController.Y());
|
||||||
lv_chart_set_next(chart, ser3, motionController.Z());
|
lv_chart_set_next(chart, ser3, motionController.Z());
|
||||||
|
|
||||||
lv_label_set_text_fmt(labelStep, "Steps %lu", motionController.NbSteps());
|
lv_label_set_text_fmt(labelStep, "Steps %lu", motionController.NbSteps());
|
||||||
|
|
||||||
lv_label_set_text_fmt(label, "X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#", motionController.X() / 0x10, motionController.Y() / 0x10, motionController.Z() / 0x10);
|
lv_label_set_text_fmt(label,
|
||||||
|
"X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#",
|
||||||
|
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, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Motion::OnButtonPushed() {
|
|
||||||
running = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,7 @@ namespace Pinetime {
|
|||||||
Motion(DisplayApp* app, Controllers::MotionController& motionController);
|
Motion(DisplayApp* app, Controllers::MotionController& motionController);
|
||||||
~Motion() override;
|
~Motion() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
bool OnButtonPushed() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Controllers::MotionController& motionController;
|
Controllers::MotionController& motionController;
|
||||||
@ -29,9 +28,7 @@ namespace Pinetime {
|
|||||||
lv_obj_t* label;
|
lv_obj_t* label;
|
||||||
|
|
||||||
lv_obj_t* labelStep;
|
lv_obj_t* labelStep;
|
||||||
static constexpr uint8_t nbStepsBufferSize = 9;
|
lv_task_t* taskRefresh;
|
||||||
char nbStepsBuffer[nbStepsBufferSize + 1];
|
|
||||||
bool running = true;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,60 +50,55 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) {
|
|||||||
Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::MusicService& music) : Screen(app), musicService(music) {
|
Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::MusicService& music) : Screen(app), musicService(music) {
|
||||||
lv_obj_t* label;
|
lv_obj_t* label;
|
||||||
|
|
||||||
|
lv_style_init(&btn_style);
|
||||||
|
lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, 20);
|
||||||
|
lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
||||||
|
lv_style_set_bg_opa(&btn_style, LV_STATE_DEFAULT, LV_OPA_20);
|
||||||
|
|
||||||
btnVolDown = lv_btn_create(lv_scr_act(), nullptr);
|
btnVolDown = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnVolDown->user_data = this;
|
btnVolDown->user_data = this;
|
||||||
lv_obj_set_event_cb(btnVolDown, event_handler);
|
lv_obj_set_event_cb(btnVolDown, event_handler);
|
||||||
lv_obj_set_size(btnVolDown, 65, 75);
|
lv_obj_set_size(btnVolDown, 76, 76);
|
||||||
lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 15, -10);
|
lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
lv_obj_set_style_local_radius(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
lv_obj_add_style(btnVolDown, LV_STATE_DEFAULT, &btn_style);
|
||||||
lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
|
||||||
lv_obj_set_style_local_bg_opa(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
|
||||||
label = lv_label_create(btnVolDown, nullptr);
|
label = lv_label_create(btnVolDown, nullptr);
|
||||||
lv_label_set_text(label, Symbols::volumDown);
|
lv_label_set_text(label, Symbols::volumDown);
|
||||||
lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
|
lv_obj_set_hidden(btnVolDown, true);
|
||||||
|
|
||||||
btnVolUp = lv_btn_create(lv_scr_act(), nullptr);
|
btnVolUp = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnVolUp->user_data = this;
|
btnVolUp->user_data = this;
|
||||||
lv_obj_set_event_cb(btnVolUp, event_handler);
|
lv_obj_set_event_cb(btnVolUp, event_handler);
|
||||||
lv_obj_set_size(btnVolUp, 65, 75);
|
lv_obj_set_size(btnVolUp, 76, 76);
|
||||||
lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10);
|
lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
lv_obj_set_style_local_radius(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
lv_obj_add_style(btnVolUp, LV_STATE_DEFAULT, &btn_style);
|
||||||
lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
|
||||||
lv_obj_set_style_local_bg_opa(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
|
||||||
label = lv_label_create(btnVolUp, nullptr);
|
label = lv_label_create(btnVolUp, nullptr);
|
||||||
lv_label_set_text(label, Symbols::volumUp);
|
lv_label_set_text(label, Symbols::volumUp);
|
||||||
lv_obj_set_hidden(btnVolUp, !displayVolumeButtons);
|
lv_obj_set_hidden(btnVolUp, true);
|
||||||
|
|
||||||
btnPrev = lv_btn_create(lv_scr_act(), nullptr);
|
btnPrev = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnPrev->user_data = this;
|
btnPrev->user_data = this;
|
||||||
lv_obj_set_event_cb(btnPrev, event_handler);
|
lv_obj_set_event_cb(btnPrev, event_handler);
|
||||||
lv_obj_set_size(btnPrev, 65, 75);
|
lv_obj_set_size(btnPrev, 76, 76);
|
||||||
lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 15, -10);
|
lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
lv_obj_set_style_local_radius(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
lv_obj_add_style(btnPrev, LV_STATE_DEFAULT, &btn_style);
|
||||||
lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
|
||||||
lv_obj_set_style_local_bg_opa(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
|
||||||
label = lv_label_create(btnPrev, nullptr);
|
label = lv_label_create(btnPrev, nullptr);
|
||||||
lv_label_set_text(label, Symbols::stepBackward);
|
lv_label_set_text(label, Symbols::stepBackward);
|
||||||
|
|
||||||
btnNext = lv_btn_create(lv_scr_act(), nullptr);
|
btnNext = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnNext->user_data = this;
|
btnNext->user_data = this;
|
||||||
lv_obj_set_event_cb(btnNext, event_handler);
|
lv_obj_set_event_cb(btnNext, event_handler);
|
||||||
lv_obj_set_size(btnNext, 65, 75);
|
lv_obj_set_size(btnNext, 76, 76);
|
||||||
lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10);
|
lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
lv_obj_set_style_local_radius(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
lv_obj_add_style(btnNext, LV_STATE_DEFAULT, &btn_style);
|
||||||
lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
|
||||||
lv_obj_set_style_local_bg_opa(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
|
||||||
label = lv_label_create(btnNext, nullptr);
|
label = lv_label_create(btnNext, nullptr);
|
||||||
lv_label_set_text(label, Symbols::stepForward);
|
lv_label_set_text(label, Symbols::stepForward);
|
||||||
|
|
||||||
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
|
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnPlayPause->user_data = this;
|
btnPlayPause->user_data = this;
|
||||||
lv_obj_set_event_cb(btnPlayPause, event_handler);
|
lv_obj_set_event_cb(btnPlayPause, event_handler);
|
||||||
lv_obj_set_size(btnPlayPause, 65, 75);
|
lv_obj_set_size(btnPlayPause, 76, 76);
|
||||||
lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -10);
|
lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||||
lv_obj_set_style_local_radius(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
lv_obj_add_style(btnPlayPause, LV_STATE_DEFAULT, &btn_style);
|
||||||
lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
|
|
||||||
lv_obj_set_style_local_bg_opa(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_20);
|
|
||||||
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
|
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
|
||||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||||
|
|
||||||
@ -119,7 +114,6 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
|
|||||||
constexpr int8_t MIDDLE_OFFSET = -25;
|
constexpr int8_t MIDDLE_OFFSET = -25;
|
||||||
txtArtist = lv_label_create(lv_scr_act(), nullptr);
|
txtArtist = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC);
|
lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC);
|
||||||
lv_label_set_anim_speed(txtArtist, 1);
|
|
||||||
lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);
|
lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);
|
||||||
lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID);
|
lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID);
|
||||||
lv_obj_set_width(txtArtist, LV_HOR_RES - 12);
|
lv_obj_set_width(txtArtist, LV_HOR_RES - 12);
|
||||||
@ -127,7 +121,6 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
|
|||||||
|
|
||||||
txtTrack = lv_label_create(lv_scr_act(), nullptr);
|
txtTrack = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC);
|
lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC);
|
||||||
lv_label_set_anim_speed(txtTrack, 1);
|
|
||||||
lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD);
|
lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD);
|
||||||
|
|
||||||
lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID);
|
lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID);
|
||||||
@ -146,13 +139,17 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
|
|||||||
frameB = false;
|
frameB = false;
|
||||||
|
|
||||||
musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN);
|
musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN);
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Music::~Music() {
|
Music::~Music() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
|
lv_style_reset(&btn_style);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Music::Refresh() {
|
void Music::Refresh() {
|
||||||
if (artist != musicService.getArtist()) {
|
if (artist != musicService.getArtist()) {
|
||||||
artist = musicService.getArtist();
|
artist = musicService.getArtist();
|
||||||
currentLength = 0;
|
currentLength = 0;
|
||||||
@ -216,8 +213,6 @@ bool Music::Refresh() {
|
|||||||
} else {
|
} else {
|
||||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||||
}
|
}
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Music::UpdateLength() {
|
void Music::UpdateLength() {
|
||||||
@ -274,21 +269,19 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) {
|
|||||||
bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case TouchEvents::SwipeUp: {
|
case TouchEvents::SwipeUp: {
|
||||||
displayVolumeButtons = true;
|
lv_obj_set_hidden(btnVolDown, false);
|
||||||
lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
|
lv_obj_set_hidden(btnVolUp, false);
|
||||||
lv_obj_set_hidden(btnVolUp, !displayVolumeButtons);
|
|
||||||
|
|
||||||
lv_obj_set_hidden(btnNext, displayVolumeButtons);
|
lv_obj_set_hidden(btnNext, true);
|
||||||
lv_obj_set_hidden(btnPrev, displayVolumeButtons);
|
lv_obj_set_hidden(btnPrev, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TouchEvents::SwipeDown: {
|
case TouchEvents::SwipeDown: {
|
||||||
displayVolumeButtons = false;
|
lv_obj_set_hidden(btnNext, false);
|
||||||
lv_obj_set_hidden(btnNext, displayVolumeButtons);
|
lv_obj_set_hidden(btnPrev, false);
|
||||||
lv_obj_set_hidden(btnPrev, displayVolumeButtons);
|
|
||||||
|
|
||||||
lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
|
lv_obj_set_hidden(btnVolDown, true);
|
||||||
lv_obj_set_hidden(btnVolUp, !displayVolumeButtons);
|
lv_obj_set_hidden(btnVolUp, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TouchEvents::SwipeLeft: {
|
case TouchEvents::SwipeLeft: {
|
||||||
@ -300,7 +293,7 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -35,7 +35,7 @@ namespace Pinetime {
|
|||||||
|
|
||||||
~Music() override;
|
~Music() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
|
void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
|
||||||
|
|
||||||
@ -57,10 +57,11 @@ namespace Pinetime {
|
|||||||
lv_obj_t* imgDiscAnim;
|
lv_obj_t* imgDiscAnim;
|
||||||
lv_obj_t* txtTrackDuration;
|
lv_obj_t* txtTrackDuration;
|
||||||
|
|
||||||
|
lv_style_t btn_style;
|
||||||
|
|
||||||
/** For the spinning disc animation */
|
/** For the spinning disc animation */
|
||||||
bool frameB;
|
bool frameB;
|
||||||
|
|
||||||
bool displayVolumeButtons = false;
|
|
||||||
Pinetime::Controllers::MusicService& musicService;
|
Pinetime::Controllers::MusicService& musicService;
|
||||||
|
|
||||||
std::string artist;
|
std::string artist;
|
||||||
@ -78,6 +79,8 @@ namespace Pinetime {
|
|||||||
|
|
||||||
bool playing;
|
bool playing;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
|
|
||||||
/** Watchapp */
|
/** Watchapp */
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -161,13 +161,16 @@ Navigation::Navigation(Pinetime::Applications::DisplayApp* app, Pinetime::Contro
|
|||||||
lv_bar_set_anim_time(barProgress, 500);
|
lv_bar_set_anim_time(barProgress, 500);
|
||||||
lv_bar_set_range(barProgress, 0, 100);
|
lv_bar_set_range(barProgress, 0, 100);
|
||||||
lv_bar_set_value(barProgress, 0, LV_ANIM_OFF);
|
lv_bar_set_value(barProgress, 0, LV_ANIM_OFF);
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Navigation::~Navigation() {
|
Navigation::~Navigation() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Navigation::Refresh() {
|
void Navigation::Refresh() {
|
||||||
if (flag != navService.getFlag()) {
|
if (flag != navService.getFlag()) {
|
||||||
flag = navService.getFlag();
|
flag = navService.getFlag();
|
||||||
lv_label_set_text(imgFlag, iconForName(flag));
|
lv_label_set_text(imgFlag, iconForName(flag));
|
||||||
@ -192,8 +195,4 @@ bool Navigation::Refresh() {
|
|||||||
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
|
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace Pinetime {
|
|||||||
Navigation(DisplayApp* app, Pinetime::Controllers::NavigationService& nav);
|
Navigation(DisplayApp* app, Pinetime::Controllers::NavigationService& nav);
|
||||||
~Navigation() override;
|
~Navigation() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lv_obj_t* imgFlag;
|
lv_obj_t* imgFlag;
|
||||||
@ -49,6 +49,8 @@ namespace Pinetime {
|
|||||||
std::string narrative;
|
std::string narrative;
|
||||||
std::string manDist;
|
std::string manDist;
|
||||||
int progress;
|
int progress;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ extern lv_font_t jetbrains_mono_bold_20;
|
|||||||
Notifications::Notifications(DisplayApp* app,
|
Notifications::Notifications(DisplayApp* app,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
||||||
|
Pinetime::Controllers::MotorController& motorController,
|
||||||
Modes mode)
|
Modes mode)
|
||||||
: Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, mode {mode} {
|
: Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, mode {mode} {
|
||||||
notificationManager.ClearNewNotificationFlag();
|
notificationManager.ClearNewNotificationFlag();
|
||||||
@ -36,25 +37,34 @@ Notifications::Notifications(DisplayApp* app,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == Modes::Preview) {
|
if (mode == Modes::Preview) {
|
||||||
|
if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) {
|
||||||
|
motorController.StartRinging();
|
||||||
|
} else {
|
||||||
|
motorController.RunForDuration(35);
|
||||||
|
timeoutLine = lv_line_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
timeoutLine = lv_line_create(lv_scr_act(), nullptr);
|
lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
||||||
|
lv_obj_set_style_local_line_color(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
|
lv_obj_set_style_local_line_rounded(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
||||||
|
|
||||||
lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
|
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
|
||||||
lv_obj_set_style_local_line_color(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
timeoutTickCountStart = xTaskGetTickCount();
|
||||||
lv_obj_set_style_local_line_rounded(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
|
timeoutTickCountEnd = timeoutTickCountStart + (5 * 1024);
|
||||||
|
}
|
||||||
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
|
|
||||||
timeoutTickCountStart = xTaskGetTickCount();
|
|
||||||
timeoutTickCountEnd = timeoutTickCountStart + (5 * 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Notifications::~Notifications() {
|
Notifications::~Notifications() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
|
// make sure we stop any vibrations before exiting
|
||||||
|
Controllers::MotorController::StopRinging();
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Notifications::Refresh() {
|
void Notifications::Refresh() {
|
||||||
if (mode == Modes::Preview) {
|
if (mode == Modes::Preview && timeoutLine != nullptr) {
|
||||||
auto tick = xTaskGetTickCount();
|
auto tick = xTaskGetTickCount();
|
||||||
int32_t pos = 240 - ((tick - timeoutTickCountStart) / ((timeoutTickCountEnd - timeoutTickCountStart) / 240));
|
int32_t pos = 240 - ((tick - timeoutTickCountStart) / ((timeoutTickCountEnd - timeoutTickCountStart) / 240));
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
@ -63,13 +73,12 @@ bool Notifications::Refresh() {
|
|||||||
timeoutLinePoints[1].x = pos;
|
timeoutLinePoints[1].x = pos;
|
||||||
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
|
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
if (mode != Modes::Normal)
|
if (mode != Modes::Normal) {
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case Pinetime::Applications::TouchEvents::SwipeDown: {
|
case Pinetime::Applications::TouchEvents::SwipeDown: {
|
||||||
@ -130,19 +139,9 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static void AcceptIncomingCallEventHandler(lv_obj_t* obj, lv_event_t event) {
|
void CallEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||||
auto* item = static_cast<Notifications::NotificationItem*>(obj->user_data);
|
auto* item = static_cast<Notifications::NotificationItem*>(obj->user_data);
|
||||||
item->OnAcceptIncomingCall(event);
|
item->OnCallButtonEvent(obj, event);
|
||||||
}
|
|
||||||
|
|
||||||
static void MuteIncomingCallEventHandler(lv_obj_t* obj, lv_event_t event) {
|
|
||||||
auto* item = static_cast<Notifications::NotificationItem*>(obj->user_data);
|
|
||||||
item->OnMuteIncomingCall(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RejectIncomingCallEventHandler(lv_obj_t* obj, lv_event_t event) {
|
|
||||||
auto* item = static_cast<Notifications::NotificationItem*>(obj->user_data);
|
|
||||||
item->OnRejectIncomingCall(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +153,6 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
Modes mode,
|
Modes mode,
|
||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService)
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService)
|
||||||
: notifNr {notifNr}, notifNb {notifNb}, mode {mode}, alertNotificationService {alertNotificationService} {
|
: notifNr {notifNr}, notifNb {notifNb}, mode {mode}, alertNotificationService {alertNotificationService} {
|
||||||
|
|
||||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL);
|
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL);
|
||||||
|
|
||||||
lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
||||||
@ -184,7 +182,6 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
}
|
}
|
||||||
lv_label_set_text(alert_type, title);
|
lv_label_set_text(alert_type, title);
|
||||||
lv_label_set_long_mode(alert_type, LV_LABEL_LONG_SROLL_CIRC);
|
lv_label_set_long_mode(alert_type, LV_LABEL_LONG_SROLL_CIRC);
|
||||||
lv_label_set_anim_speed(alert_type, 3);
|
|
||||||
lv_obj_set_width(alert_type, 180);
|
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, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16);
|
||||||
|
|
||||||
@ -213,7 +210,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
|
|
||||||
bt_accept = lv_btn_create(lv_scr_act(), nullptr);
|
bt_accept = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
bt_accept->user_data = this;
|
bt_accept->user_data = this;
|
||||||
lv_obj_set_event_cb(bt_accept, AcceptIncomingCallEventHandler);
|
lv_obj_set_event_cb(bt_accept, CallEventHandler);
|
||||||
lv_obj_set_size(bt_accept, 76, 76);
|
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, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
label_accept = lv_label_create(bt_accept, nullptr);
|
label_accept = lv_label_create(bt_accept, nullptr);
|
||||||
@ -222,7 +219,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
|
|
||||||
bt_reject = lv_btn_create(lv_scr_act(), nullptr);
|
bt_reject = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
bt_reject->user_data = this;
|
bt_reject->user_data = this;
|
||||||
lv_obj_set_event_cb(bt_reject, RejectIncomingCallEventHandler);
|
lv_obj_set_event_cb(bt_reject, CallEventHandler);
|
||||||
lv_obj_set_size(bt_reject, 76, 76);
|
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, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||||
label_reject = lv_label_create(bt_reject, nullptr);
|
label_reject = lv_label_create(bt_reject, nullptr);
|
||||||
@ -231,7 +228,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
|
|
||||||
bt_mute = lv_btn_create(lv_scr_act(), nullptr);
|
bt_mute = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
bt_mute->user_data = this;
|
bt_mute->user_data = this;
|
||||||
lv_obj_set_event_cb(bt_mute, MuteIncomingCallEventHandler);
|
lv_obj_set_event_cb(bt_mute, CallEventHandler);
|
||||||
lv_obj_set_size(bt_mute, 76, 76);
|
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, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
label_mute = lv_label_create(bt_mute, nullptr);
|
label_mute = lv_label_create(bt_mute, nullptr);
|
||||||
@ -247,25 +244,22 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
lv_label_set_text(backgroundLabel, "");
|
lv_label_set_text(backgroundLabel, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notifications::NotificationItem::OnAcceptIncomingCall(lv_event_t event) {
|
void Notifications::NotificationItem::OnCallButtonEvent(lv_obj_t* obj, lv_event_t event) {
|
||||||
if (event != LV_EVENT_CLICKED)
|
if (event != LV_EVENT_CLICKED) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
alertNotificationService.AcceptIncomingCall();
|
Controllers::MotorController::StopRinging();
|
||||||
}
|
|
||||||
|
|
||||||
void Notifications::NotificationItem::OnMuteIncomingCall(lv_event_t event) {
|
if (obj == bt_accept) {
|
||||||
if (event != LV_EVENT_CLICKED)
|
alertNotificationService.AcceptIncomingCall();
|
||||||
return;
|
} else if (obj == bt_reject) {
|
||||||
|
alertNotificationService.RejectIncomingCall();
|
||||||
|
} else if (obj == bt_mute) {
|
||||||
|
alertNotificationService.MuteIncomingCall();
|
||||||
|
}
|
||||||
|
|
||||||
alertNotificationService.MuteIncomingCall();
|
running = false;
|
||||||
}
|
|
||||||
|
|
||||||
void Notifications::NotificationItem::OnRejectIncomingCall(lv_event_t event) {
|
|
||||||
if (event != LV_EVENT_CLICKED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
alertNotificationService.RejectIncomingCall();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Notifications::NotificationItem::~NotificationItem() {
|
Notifications::NotificationItem::~NotificationItem() {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include "components/ble/NotificationManager.h"
|
#include "components/ble/NotificationManager.h"
|
||||||
|
#include "components/motor/MotorController.h"
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Controllers {
|
namespace Controllers {
|
||||||
@ -19,10 +20,11 @@ namespace Pinetime {
|
|||||||
explicit Notifications(DisplayApp* app,
|
explicit Notifications(DisplayApp* app,
|
||||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
||||||
|
Pinetime::Controllers::MotorController& motorController,
|
||||||
Modes mode);
|
Modes mode);
|
||||||
~Notifications() override;
|
~Notifications() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||||
|
|
||||||
class NotificationItem {
|
class NotificationItem {
|
||||||
@ -35,12 +37,10 @@ namespace Pinetime {
|
|||||||
Modes mode,
|
Modes mode,
|
||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService);
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService);
|
||||||
~NotificationItem();
|
~NotificationItem();
|
||||||
bool Refresh() {
|
bool IsRunning() const {
|
||||||
return false;
|
return running;
|
||||||
}
|
}
|
||||||
void OnAcceptIncomingCall(lv_event_t event);
|
void OnCallButtonEvent(lv_obj_t*, lv_event_t event);
|
||||||
void OnMuteIncomingCall(lv_event_t event);
|
|
||||||
void OnRejectIncomingCall(lv_event_t event);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t notifNr = 0;
|
uint8_t notifNr = 0;
|
||||||
@ -60,6 +60,7 @@ namespace Pinetime {
|
|||||||
lv_obj_t* bottomPlaceholder;
|
lv_obj_t* bottomPlaceholder;
|
||||||
Modes mode;
|
Modes mode;
|
||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
|
||||||
|
bool running = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -75,9 +76,11 @@ namespace Pinetime {
|
|||||||
bool validDisplay = false;
|
bool validDisplay = false;
|
||||||
|
|
||||||
lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}};
|
lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}};
|
||||||
lv_obj_t* timeoutLine;
|
lv_obj_t* timeoutLine = nullptr;
|
||||||
uint32_t timeoutTickCountStart;
|
uint32_t timeoutTickCountStart;
|
||||||
uint32_t timeoutTickCountEnd;
|
uint32_t timeoutTickCountEnd;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
Paddle::Paddle(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
Paddle::Paddle(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
|
||||||
|
|
||||||
background = lv_obj_create(lv_scr_act(), nullptr);
|
background = lv_obj_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_size(background, LV_HOR_RES + 1, LV_VER_RES);
|
lv_obj_set_size(background, LV_HOR_RES + 1, LV_VER_RES);
|
||||||
lv_obj_set_pos(background, -1, 0);
|
lv_obj_set_pos(background, -1, 0);
|
||||||
@ -29,15 +27,16 @@ Paddle::Paddle(Pinetime::Applications::DisplayApp* app, Pinetime::Components::Li
|
|||||||
lv_obj_set_style_local_bg_color(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
lv_obj_set_style_local_bg_color(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
lv_obj_set_style_local_radius(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_obj_set_style_local_radius(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
lv_obj_set_size(ball, ballSize, ballSize);
|
lv_obj_set_size(ball, ballSize, ballSize);
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Paddle::~Paddle() {
|
Paddle::~Paddle() {
|
||||||
// Reset the touchmode
|
lv_task_del(taskRefresh);
|
||||||
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Paddle::Refresh() {
|
void Paddle::Refresh() {
|
||||||
ballX += dx;
|
ballX += dx;
|
||||||
ballY += dy;
|
ballY += dy;
|
||||||
|
|
||||||
@ -69,7 +68,6 @@ bool Paddle::Refresh() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lv_label_set_text_fmt(points, "%04d", score);
|
lv_label_set_text_fmt(points, "%04d", score);
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
|
@ -16,7 +16,7 @@ namespace Pinetime {
|
|||||||
Paddle(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl);
|
Paddle(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl);
|
||||||
~Paddle() override;
|
~Paddle() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
bool OnTouchEvent(uint16_t x, uint16_t y) override;
|
bool OnTouchEvent(uint16_t x, uint16_t y) override;
|
||||||
@ -40,6 +40,8 @@ namespace Pinetime {
|
|||||||
lv_obj_t* paddle;
|
lv_obj_t* paddle;
|
||||||
lv_obj_t* ball;
|
lv_obj_t* ball;
|
||||||
lv_obj_t* background;
|
lv_obj_t* background;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <date/date.h>
|
#include <date/date.h>
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <displayapp/Colors.h>
|
||||||
#include "BatteryIcon.h"
|
#include "BatteryIcon.h"
|
||||||
#include "BleIcon.h"
|
#include "BleIcon.h"
|
||||||
#include "NotificationIcon.h"
|
#include "NotificationIcon.h"
|
||||||
@ -52,7 +53,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
|||||||
settingsController {settingsController},
|
settingsController {settingsController},
|
||||||
motionController {motionController} {
|
motionController {motionController} {
|
||||||
|
|
||||||
/* This sets the watchface number to return to after leaving the menu */
|
// This sets the watchface number to return to after leaving the menu
|
||||||
settingsController.SetClockFace(2);
|
settingsController.SetClockFace(2);
|
||||||
|
|
||||||
displayedChar[0] = 0;
|
displayedChar[0] = 0;
|
||||||
@ -61,44 +62,40 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
|||||||
displayedChar[3] = 0;
|
displayedChar[3] = 0;
|
||||||
displayedChar[4] = 0;
|
displayedChar[4] = 0;
|
||||||
|
|
||||||
/* Create a 200px wide background rectangle */
|
//Create a 200px wide background rectangle
|
||||||
|
|
||||||
timebar = lv_obj_create(lv_scr_act(), nullptr);
|
timebar = lv_obj_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBG()));
|
||||||
lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
lv_obj_set_size(timebar, 200, 240);
|
lv_obj_set_size(timebar, 200, 240);
|
||||||
lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0);
|
lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0);
|
||||||
|
|
||||||
/* Display the time */
|
// Display the time
|
||||||
|
|
||||||
timeDD1 = lv_label_create(lv_scr_act(), nullptr);
|
timeDD1 = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
|
lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
|
||||||
lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
|
lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
|
||||||
lv_label_set_text(timeDD1, "12");
|
lv_label_set_text(timeDD1, "12");
|
||||||
lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
|
lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
|
||||||
|
|
||||||
timeDD2 = lv_label_create(lv_scr_act(), nullptr);
|
timeDD2 = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
|
lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
|
||||||
lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
|
lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
|
||||||
lv_label_set_text(timeDD2, "34");
|
lv_label_set_text(timeDD2, "34");
|
||||||
lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
|
lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
|
||||||
|
|
||||||
timeAMPM = lv_label_create(lv_scr_act(), nullptr);
|
timeAMPM = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
|
lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
|
||||||
lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3);
|
lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3);
|
||||||
lv_label_set_text(timeAMPM, "");
|
lv_label_set_text(timeAMPM, "");
|
||||||
lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20);
|
lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20);
|
||||||
|
|
||||||
/* Create a 40px wide bar down the right side of the screen */
|
// Create a 40px wide bar down the right side of the screen
|
||||||
|
|
||||||
sidebar = lv_obj_create(lv_scr_act(), nullptr);
|
sidebar = lv_obj_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
|
lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBar()));
|
||||||
lv_obj_set_style_local_radius(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
lv_obj_set_style_local_radius(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
lv_obj_set_size(sidebar, 40, 240);
|
lv_obj_set_size(sidebar, 40, 240);
|
||||||
lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||||
|
|
||||||
/* Display icons */
|
// Display icons
|
||||||
|
|
||||||
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
|
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
lv_label_set_text(batteryIcon, Symbols::batteryFull);
|
lv_label_set_text(batteryIcon, Symbols::batteryFull);
|
||||||
@ -116,8 +113,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
|||||||
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 40);
|
lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 40);
|
||||||
|
|
||||||
/* Calendar icon */
|
// Calendar icon
|
||||||
|
|
||||||
calendarOuter = lv_obj_create(lv_scr_act(), nullptr);
|
calendarOuter = lv_obj_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
@ -154,8 +150,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
|||||||
lv_obj_set_size(calendarCrossBar2, 8, 3);
|
lv_obj_set_size(calendarCrossBar2, 8, 3);
|
||||||
lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||||
|
|
||||||
/* Display date */
|
// Display date
|
||||||
|
|
||||||
dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr);
|
dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||||
lv_label_set_text(dateDayOfWeek, "THU");
|
lv_label_set_text(dateDayOfWeek, "THU");
|
||||||
@ -191,7 +186,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
|||||||
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4);
|
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4);
|
||||||
lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||||
lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
|
lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 3);
|
||||||
lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
|
lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
|
||||||
|
|
||||||
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||||
@ -200,13 +195,17 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
|||||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||||
lv_label_set_text(backgroundLabel, "");
|
lv_label_set_text(backgroundLabel, "");
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
PineTimeStyle::~PineTimeStyle() {
|
PineTimeStyle::~PineTimeStyle() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PineTimeStyle::Refresh() {
|
void PineTimeStyle::Refresh() {
|
||||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||||
if (batteryPercentRemaining.IsUpdated()) {
|
if (batteryPercentRemaining.IsUpdated()) {
|
||||||
auto batteryPercent = batteryPercentRemaining.Get();
|
auto batteryPercent = batteryPercentRemaining.Get();
|
||||||
@ -223,26 +222,17 @@ bool PineTimeStyle::Refresh() {
|
|||||||
|
|
||||||
bleState = bleController.IsConnected();
|
bleState = bleController.IsConnected();
|
||||||
if (bleState.IsUpdated()) {
|
if (bleState.IsUpdated()) {
|
||||||
if (bleState.Get() == true) {
|
lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get()));
|
||||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(true));
|
lv_obj_realign(bleIcon);
|
||||||
lv_obj_realign(bleIcon);
|
|
||||||
} else {
|
|
||||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||||
if (notificationState.IsUpdated()) {
|
if (notificationState.IsUpdated()) {
|
||||||
if (notificationState.Get() == true) {
|
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
|
||||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
|
lv_obj_realign(notificationIcon);
|
||||||
lv_obj_realign(notificationIcon);
|
|
||||||
} else {
|
|
||||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDateTime = dateTimeController.CurrentDateTime();
|
currentDateTime = dateTimeController.CurrentDateTime();
|
||||||
|
|
||||||
if (currentDateTime.IsUpdated()) {
|
if (currentDateTime.IsUpdated()) {
|
||||||
auto newDateTime = currentDateTime.Get();
|
auto newDateTime = currentDateTime.Get();
|
||||||
|
|
||||||
@ -250,9 +240,9 @@ bool PineTimeStyle::Refresh() {
|
|||||||
auto time = date::make_time(newDateTime - dp);
|
auto time = date::make_time(newDateTime - dp);
|
||||||
auto yearMonthDay = date::year_month_day(dp);
|
auto yearMonthDay = date::year_month_day(dp);
|
||||||
|
|
||||||
auto year = (int) yearMonthDay.year();
|
auto year = static_cast<int>(yearMonthDay.year());
|
||||||
auto month = static_cast<Pinetime::Controllers::DateTime::Months>((unsigned) yearMonthDay.month());
|
auto month = static_cast<Pinetime::Controllers::DateTime::Months>(static_cast<unsigned>(yearMonthDay.month()));
|
||||||
auto day = (unsigned) yearMonthDay.day();
|
auto day = static_cast<unsigned>(yearMonthDay.day());
|
||||||
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
|
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||||
|
|
||||||
int hour = time.hours().count();
|
int hour = time.hours().count();
|
||||||
@ -263,60 +253,44 @@ bool PineTimeStyle::Refresh() {
|
|||||||
|
|
||||||
char hoursChar[3];
|
char hoursChar[3];
|
||||||
char ampmChar[5];
|
char ampmChar[5];
|
||||||
|
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
|
||||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
|
|
||||||
sprintf(hoursChar, "%02d", hour);
|
|
||||||
} else {
|
|
||||||
if (hour == 0 && hour != 12) {
|
|
||||||
hour = 12;
|
|
||||||
sprintf(ampmChar, "A\nM");
|
|
||||||
} else if (hour == 12 && hour != 0) {
|
|
||||||
hour = 12;
|
|
||||||
sprintf(ampmChar, "P\nM");
|
|
||||||
} else if (hour < 12 && hour != 0) {
|
|
||||||
sprintf(ampmChar, "A\nM");
|
|
||||||
} else if (hour > 12 && hour != 0) {
|
|
||||||
hour = hour - 12;
|
|
||||||
sprintf(ampmChar, "P\nM");
|
|
||||||
}
|
|
||||||
sprintf(hoursChar, "%02d", hour);
|
sprintf(hoursChar, "%02d", hour);
|
||||||
|
} else {
|
||||||
|
if (hour == 0 && hour != 12) {
|
||||||
|
hour = 12;
|
||||||
|
sprintf(ampmChar, "A\nM");
|
||||||
|
} else if (hour == 12 && hour != 0) {
|
||||||
|
hour = 12;
|
||||||
|
sprintf(ampmChar, "P\nM");
|
||||||
|
} else if (hour < 12 && hour != 0) {
|
||||||
|
sprintf(ampmChar, "A\nM");
|
||||||
|
} else if (hour > 12 && hour != 0) {
|
||||||
|
hour = hour - 12;
|
||||||
|
sprintf(ampmChar, "P\nM");
|
||||||
}
|
}
|
||||||
|
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]) {
|
minutesChar[1] != displayedChar[3]) {
|
||||||
displayedChar[0] = hoursChar[0];
|
displayedChar[0] = hoursChar[0];
|
||||||
displayedChar[1] = hoursChar[1];
|
displayedChar[1] = hoursChar[1];
|
||||||
displayedChar[2] = minutesChar[0];
|
displayedChar[2] = minutesChar[0];
|
||||||
displayedChar[3] = minutesChar[1];
|
displayedChar[3] = minutesChar[1];
|
||||||
|
|
||||||
char hourStr[3];
|
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||||
char minStr[3];
|
|
||||||
|
|
||||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
|
||||||
lv_label_set_text(timeAMPM, ampmChar);
|
lv_label_set_text(timeAMPM, ampmChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Display the time as 2 pairs of digits */
|
lv_label_set_text_fmt(timeDD1, "%s", hoursChar);
|
||||||
sprintf(hourStr, "%c%c", hoursChar[0], hoursChar[1]);
|
lv_label_set_text_fmt(timeDD2, "%s", minutesChar);
|
||||||
lv_label_set_text(timeDD1, hourStr);
|
|
||||||
|
|
||||||
sprintf(minStr, "%c%c", minutesChar[0], minutesChar[1]);
|
|
||||||
lv_label_set_text(timeDD2, minStr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||||
char dayOfWeekStr[4];
|
lv_label_set_text_fmt(dateDayOfWeek, "%s", dateTimeController.DayOfWeekShortToString());
|
||||||
char dayStr[3];
|
lv_label_set_text_fmt(dateDay, "%d", day);
|
||||||
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_obj_realign(dateDay);
|
lv_obj_realign(dateDay);
|
||||||
lv_label_set_text(dateMonth, monthStr);
|
lv_label_set_text_fmt(dateMonth, "%s", dateTimeController.MonthShortToString());
|
||||||
|
|
||||||
currentYear = year;
|
currentYear = year;
|
||||||
currentMonth = month;
|
currentMonth = month;
|
||||||
@ -335,6 +309,4 @@ bool PineTimeStyle::Refresh() {
|
|||||||
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
@ -30,9 +30,7 @@ namespace Pinetime {
|
|||||||
Controllers::MotionController& motionController);
|
Controllers::MotionController& motionController);
|
||||||
~PineTimeStyle() override;
|
~PineTimeStyle() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
void OnObjectEvent(lv_obj_t* pObj, lv_event_t i);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char displayedChar[5];
|
char displayedChar[5];
|
||||||
@ -67,9 +65,6 @@ namespace Pinetime {
|
|||||||
lv_obj_t* calendarBar2;
|
lv_obj_t* calendarBar2;
|
||||||
lv_obj_t* calendarCrossBar1;
|
lv_obj_t* calendarCrossBar1;
|
||||||
lv_obj_t* calendarCrossBar2;
|
lv_obj_t* calendarCrossBar2;
|
||||||
lv_obj_t* heartbeatIcon;
|
|
||||||
lv_obj_t* heartbeatValue;
|
|
||||||
lv_obj_t* heartbeatBpm;
|
|
||||||
lv_obj_t* notificationIcon;
|
lv_obj_t* notificationIcon;
|
||||||
lv_obj_t* stepGauge;
|
lv_obj_t* stepGauge;
|
||||||
lv_color_t needle_colors[1];
|
lv_color_t needle_colors[1];
|
||||||
@ -80,6 +75,8 @@ namespace Pinetime {
|
|||||||
Controllers::NotificationManager& notificatioManager;
|
Controllers::NotificationManager& notificatioManager;
|
||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
Controllers::MotionController& motionController;
|
Controllers::MotionController& motionController;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,6 @@
|
|||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
void Screen::RefreshTaskCallback(lv_task_t* task) {
|
||||||
|
static_cast<Screen*>(task->user_data)->Refresh();
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "../TouchEvents.h"
|
#include "../TouchEvents.h"
|
||||||
|
#include <lvgl/lvgl.h>
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
@ -13,8 +14,12 @@ namespace Pinetime {
|
|||||||
DirtyValue() = default; // Use NSDMI
|
DirtyValue() = default; // Use NSDMI
|
||||||
explicit DirtyValue(T const& v) : value {v} {
|
explicit DirtyValue(T const& v) : value {v} {
|
||||||
} // Use MIL and const-lvalue-ref
|
} // Use MIL and const-lvalue-ref
|
||||||
bool IsUpdated() const {
|
bool IsUpdated() {
|
||||||
return isUpdated;
|
if (this->isUpdated) {
|
||||||
|
this->isUpdated = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
T const& Get() {
|
T const& Get() {
|
||||||
this->isUpdated = false;
|
this->isUpdated = false;
|
||||||
@ -34,25 +39,20 @@ namespace Pinetime {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Screen {
|
class Screen {
|
||||||
|
private:
|
||||||
|
virtual void Refresh() {
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Screen(DisplayApp* app) : app {app} {
|
explicit Screen(DisplayApp* app) : app {app} {
|
||||||
}
|
}
|
||||||
virtual ~Screen() = default;
|
virtual ~Screen() = default;
|
||||||
|
|
||||||
/**
|
static void RefreshTaskCallback(lv_task_t* task);
|
||||||
* Most of the time, apps only react to events (touch events, for example).
|
|
||||||
* In this case you don't need to do anything in this method.
|
bool IsRunning() const {
|
||||||
*
|
return running;
|
||||||
* For example, InfiniPaint does nothing in Refresh().
|
}
|
||||||
* But, if you want to update your display periodically, draw an animation...
|
|
||||||
* you cannot do it in a touch event handler because these handlers are not
|
|
||||||
* called if the user does not touch the screen.
|
|
||||||
*
|
|
||||||
* That's why Refresh() is there: update the display periodically.
|
|
||||||
*
|
|
||||||
* @return false if the app can be closed, true if it must continue to run
|
|
||||||
**/
|
|
||||||
virtual bool Refresh() = 0;
|
|
||||||
|
|
||||||
/** @return false if the button hasn't been handled by the app, true if it has been handled */
|
/** @return false if the button hasn't been handled by the app, true if it has been handled */
|
||||||
virtual bool OnButtonPushed() {
|
virtual bool OnButtonPushed() {
|
||||||
@ -60,6 +60,7 @@ namespace Pinetime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return false if the event hasn't been handled by the app, true if it has been handled */
|
/** @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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,6 @@ namespace Pinetime {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Refresh() override {
|
|
||||||
running = current->Refresh();
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override {
|
bool OnTouchEvent(TouchEvents event) override {
|
||||||
|
|
||||||
if (mode == ScreenListModes::UpDown) {
|
if (mode == ScreenListModes::UpDown) {
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
Steps::Steps(
|
Steps::Steps(Pinetime::Applications::DisplayApp* app,
|
||||||
Pinetime::Applications::DisplayApp *app,
|
Controllers::MotionController& motionController,
|
||||||
Controllers::MotionController& motionController,
|
Controllers::Settings& settingsController)
|
||||||
Controllers::Settings &settingsController)
|
: Screen(app), motionController {motionController}, settingsController {settingsController} {
|
||||||
: Screen(app),
|
|
||||||
motionController{motionController},
|
|
||||||
settingsController{settingsController} {
|
|
||||||
|
|
||||||
stepsArc = lv_arc_create(lv_scr_act(), nullptr);
|
stepsArc = lv_arc_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
@ -34,12 +31,12 @@ Steps::Steps(
|
|||||||
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
|
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
|
||||||
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
|
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
|
||||||
|
|
||||||
lv_obj_t * lstepsL = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_t* lstepsL = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(lstepsL, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
lv_obj_set_style_local_text_color(lstepsL, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
||||||
lv_label_set_text_static(lstepsL, "Steps");
|
lv_label_set_text_static(lstepsL, "Steps");
|
||||||
lv_obj_align(lstepsL, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
lv_obj_align(lstepsL, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
||||||
|
|
||||||
lv_obj_t * lstepsGoal = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_t* lstepsGoal = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_color(lstepsGoal, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
|
lv_obj_set_style_local_text_color(lstepsGoal, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
|
||||||
lv_label_set_text_fmt(lstepsGoal, "Goal\n%lu", settingsController.GetStepsGoal());
|
lv_label_set_text_fmt(lstepsGoal, "Goal\n%lu", settingsController.GetStepsGoal());
|
||||||
lv_label_set_align(lstepsGoal, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(lstepsGoal, LV_LABEL_ALIGN_CENTER);
|
||||||
@ -50,20 +47,20 @@ Steps::Steps(
|
|||||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||||
lv_label_set_text_static(backgroundLabel, "");
|
lv_label_set_text_static(backgroundLabel, "");
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Steps::~Steps() {
|
Steps::~Steps() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Steps::Refresh() {
|
void Steps::Refresh() {
|
||||||
|
|
||||||
stepsCount = motionController.NbSteps();
|
stepsCount = motionController.NbSteps();
|
||||||
|
|
||||||
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
|
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
|
||||||
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
|
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
|
||||||
|
|
||||||
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
|
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
@ -15,24 +15,23 @@ namespace Pinetime {
|
|||||||
namespace Screens {
|
namespace Screens {
|
||||||
|
|
||||||
class Steps : public Screen {
|
class Steps : public Screen {
|
||||||
public:
|
public:
|
||||||
Steps(DisplayApp* app, Controllers::MotionController& motionController, Controllers::Settings &settingsController);
|
Steps(DisplayApp* app, Controllers::MotionController& motionController, Controllers::Settings& settingsController);
|
||||||
~Steps() override;
|
~Steps() override;
|
||||||
|
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Controllers::MotionController& motionController;
|
||||||
|
Controllers::Settings& settingsController;
|
||||||
|
|
||||||
private:
|
lv_obj_t* lSteps;
|
||||||
|
lv_obj_t* lStepsIcon;
|
||||||
|
lv_obj_t* stepsArc;
|
||||||
|
|
||||||
Controllers::MotionController& motionController;
|
uint32_t stepsCount;
|
||||||
Controllers::Settings& settingsController;
|
|
||||||
|
|
||||||
lv_obj_t * lSteps;
|
|
||||||
lv_obj_t * lStepsIcon;
|
|
||||||
lv_obj_t * stepsArc;
|
|
||||||
|
|
||||||
uint32_t stepsCount;
|
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) {
|
|||||||
StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
|
StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
|
||||||
: Screen(app),
|
: Screen(app),
|
||||||
systemTask {systemTask},
|
systemTask {systemTask},
|
||||||
running {true},
|
|
||||||
currentState {States::Init},
|
currentState {States::Init},
|
||||||
startTime {},
|
startTime {},
|
||||||
oldTimeElapsed {},
|
oldTimeElapsed {},
|
||||||
@ -101,9 +100,12 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
|
|||||||
lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||||
lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55);
|
lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55);
|
||||||
lv_label_set_text(lapTwoText, "");
|
lv_label_set_text(lapTwoText, "");
|
||||||
|
|
||||||
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
StopWatch::~StopWatch() {
|
StopWatch::~StopWatch() {
|
||||||
|
lv_task_del(taskRefresh);
|
||||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
@ -149,7 +151,7 @@ void StopWatch::pause() {
|
|||||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StopWatch::Refresh() {
|
void StopWatch::Refresh() {
|
||||||
if (currentState == States::Running) {
|
if (currentState == States::Running) {
|
||||||
timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
|
timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
|
||||||
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
|
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
|
||||||
@ -157,11 +159,10 @@ bool StopWatch::Refresh() {
|
|||||||
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
|
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
|
||||||
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
|
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
|
||||||
}
|
}
|
||||||
return running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopWatch::playPauseBtnEventHandler(lv_event_t event) {
|
void StopWatch::playPauseBtnEventHandler(lv_event_t event) {
|
||||||
if (event != LV_EVENT_PRESSED) {
|
if (event != LV_EVENT_CLICKED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentState == States::Init) {
|
if (currentState == States::Init) {
|
||||||
@ -174,7 +175,7 @@ void StopWatch::playPauseBtnEventHandler(lv_event_t event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
|
void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
|
||||||
if (event != LV_EVENT_PRESSED) {
|
if (event != LV_EVENT_CLICKED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If running, then this button is used to save laps
|
// If running, then this button is used to save laps
|
||||||
@ -196,8 +197,7 @@ void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
|
|||||||
bool StopWatch::OnButtonPushed() {
|
bool StopWatch::OnButtonPushed() {
|
||||||
if (currentState == States::Running) {
|
if (currentState == States::Running) {
|
||||||
pause();
|
pause();
|
||||||
} else {
|
return true;
|
||||||
running = false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ namespace Pinetime::Applications::Screens {
|
|||||||
public:
|
public:
|
||||||
StopWatch(DisplayApp* app, System::SystemTask& systemTask);
|
StopWatch(DisplayApp* app, System::SystemTask& systemTask);
|
||||||
~StopWatch() override;
|
~StopWatch() override;
|
||||||
bool Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
void playPauseBtnEventHandler(lv_event_t event);
|
void playPauseBtnEventHandler(lv_event_t event);
|
||||||
void stopLapBtnEventHandler(lv_event_t event);
|
void stopLapBtnEventHandler(lv_event_t event);
|
||||||
@ -77,7 +77,6 @@ namespace Pinetime::Applications::Screens {
|
|||||||
private:
|
private:
|
||||||
Pinetime::System::SystemTask& systemTask;
|
Pinetime::System::SystemTask& systemTask;
|
||||||
TickType_t timeElapsed;
|
TickType_t timeElapsed;
|
||||||
bool running;
|
|
||||||
States currentState;
|
States currentState;
|
||||||
TickType_t startTime;
|
TickType_t startTime;
|
||||||
TickType_t oldTimeElapsed;
|
TickType_t oldTimeElapsed;
|
||||||
@ -86,5 +85,7 @@ namespace Pinetime::Applications::Screens {
|
|||||||
int lapNr = 0;
|
int lapNr = 0;
|
||||||
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
|
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
|
||||||
lv_obj_t *lapOneText, *lapTwoText;
|
lv_obj_t *lapOneText, *lapTwoText;
|
||||||
|
|
||||||
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@ namespace Pinetime {
|
|||||||
static constexpr const char* hourGlass = "\xEF\x89\x92";
|
static constexpr const char* hourGlass = "\xEF\x89\x92";
|
||||||
static constexpr const char* lapsFlag = "\xEF\x80\xA4";
|
static constexpr const char* lapsFlag = "\xEF\x80\xA4";
|
||||||
static constexpr const char* drum = "\xEF\x95\xA9";
|
static constexpr const char* drum = "\xEF\x95\xA9";
|
||||||
|
static constexpr const char* chartLine = "\xEF\x88\x81";
|
||||||
|
static constexpr const char* eye = "\xEF\x81\xAE";
|
||||||
|
static constexpr const char* home = "\xEF\x80\x95";
|
||||||
|
|
||||||
// lv_font_sys_48.c
|
// lv_font_sys_48.c
|
||||||
static constexpr const char* settings = "\xEE\xA4\x82"; // e902
|
static constexpr const char* settings = "\xEE\xA4\x82"; // e902
|
||||||
|
@ -20,6 +20,8 @@ namespace {
|
|||||||
return "BMA421";
|
return "BMA421";
|
||||||
case Pinetime::Controllers::MotionController::DeviceTypes::BMA425:
|
case Pinetime::Controllers::MotionController::DeviceTypes::BMA425:
|
||||||
return "BMA425";
|
return "BMA425";
|
||||||
|
case Pinetime::Controllers::MotionController::DeviceTypes::Unknown:
|
||||||
|
return "???";
|
||||||
}
|
}
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
@ -63,18 +65,6 @@ SystemInfo::~SystemInfo() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemInfo::Refresh() {
|
|
||||||
if (running) {
|
|
||||||
screens.Refresh();
|
|
||||||
}
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemInfo::OnButtonPushed() {
|
|
||||||
running = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
return screens.OnTouchEvent(event);
|
return screens.OnTouchEvent(event);
|
||||||
}
|
}
|
||||||
@ -210,30 +200,52 @@ bool SystemInfo::sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
|
std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
|
||||||
TaskStatus_t tasksStatus[7];
|
TaskStatus_t tasksStatus[10];
|
||||||
lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
|
lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
|
||||||
lv_table_set_col_cnt(infoTask, 3);
|
lv_table_set_col_cnt(infoTask, 4);
|
||||||
lv_table_set_row_cnt(infoTask, 8);
|
lv_table_set_row_cnt(infoTask, 8);
|
||||||
lv_obj_set_pos(infoTask, 10, 10);
|
lv_obj_set_pos(infoTask, 0, 10);
|
||||||
|
|
||||||
lv_table_set_cell_value(infoTask, 0, 0, "#");
|
lv_table_set_cell_value(infoTask, 0, 0, "#");
|
||||||
lv_table_set_col_width(infoTask, 0, 50);
|
lv_table_set_col_width(infoTask, 0, 30);
|
||||||
lv_table_set_cell_value(infoTask, 0, 1, "Task");
|
lv_table_set_cell_value(infoTask, 0, 1, "S"); // State
|
||||||
lv_table_set_col_width(infoTask, 1, 80);
|
lv_table_set_col_width(infoTask, 1, 30);
|
||||||
lv_table_set_cell_value(infoTask, 0, 2, "Free");
|
lv_table_set_cell_value(infoTask, 0, 2, "Task");
|
||||||
lv_table_set_col_width(infoTask, 2, 90);
|
lv_table_set_col_width(infoTask, 2, 80);
|
||||||
|
lv_table_set_cell_value(infoTask, 0, 3, "Free");
|
||||||
|
lv_table_set_col_width(infoTask, 3, 90);
|
||||||
|
|
||||||
auto nb = uxTaskGetSystemState(tasksStatus, 7, nullptr);
|
auto nb = uxTaskGetSystemState(tasksStatus, sizeof(tasksStatus) / sizeof(tasksStatus[0]), nullptr);
|
||||||
std::sort(tasksStatus, tasksStatus + nb, sortById);
|
std::sort(tasksStatus, tasksStatus + nb, sortById);
|
||||||
for (uint8_t i = 0; i < nb; i++) {
|
for (uint8_t i = 0; i < nb && i < 7; i++) {
|
||||||
|
|
||||||
lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
|
lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
|
||||||
lv_table_set_cell_value(infoTask, i + 1, 1, tasksStatus[i].pcTaskName);
|
char state[2] = {0};
|
||||||
|
switch (tasksStatus[i].eCurrentState) {
|
||||||
|
case eReady:
|
||||||
|
case eRunning:
|
||||||
|
state[0] = 'R';
|
||||||
|
break;
|
||||||
|
case eBlocked:
|
||||||
|
state[0] = 'B';
|
||||||
|
break;
|
||||||
|
case eSuspended:
|
||||||
|
state[0] = 'S';
|
||||||
|
break;
|
||||||
|
case eDeleted:
|
||||||
|
state[0] = 'D';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state[0] = 'I'; // Invalid
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lv_table_set_cell_value(infoTask, i + 1, 1, state);
|
||||||
|
lv_table_set_cell_value(infoTask, i + 1, 2, tasksStatus[i].pcTaskName);
|
||||||
if (tasksStatus[i].usStackHighWaterMark < 20) {
|
if (tasksStatus[i].usStackHighWaterMark < 20) {
|
||||||
std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
|
std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
|
||||||
lv_table_set_cell_value(infoTask, i + 1, 2, str1.c_str());
|
lv_table_set_cell_value(infoTask, i + 1, 3, str1.c_str());
|
||||||
} else {
|
} else {
|
||||||
lv_table_set_cell_value(infoTask, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
|
lv_table_set_cell_value(infoTask, i + 1, 3, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_unique<Screens::Label>(3, 5, app, infoTask);
|
return std::make_unique<Screens::Label>(3, 5, app, infoTask);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user