summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug-report.yaml59
-rw-r--r--.github/ISSUE_TEMPLATE/feature-request.yaml41
-rw-r--r--.github/workflows/main.yml32
-rw-r--r--.gitignore6
-rw-r--r--.vscode/settings.json52
-rw-r--r--CMakeLists.txt11
-rw-r--r--README.md32
-rwxr-xr-xcmake-nRF5x/readme.md2
-rw-r--r--doc/MemoryAnalysis.md18
-rw-r--r--doc/NavigationService.md10
-rw-r--r--doc/buildAndProgram.md7
-rw-r--r--doc/buildWithVScode.md12
-rw-r--r--doc/code/Apps.md106
-rw-r--r--doc/code/Intro.md42
-rw-r--r--doc/contribute.md20
-rw-r--r--doc/filesInReleaseNotes.md4
-rw-r--r--doc/gettingStarted/gettingStarted-1.0.md12
-rw-r--r--doc/gettingStarted/ota-gadgetbridge-nrfconnect.md10
-rw-r--r--doc/versioning.md2
-rw-r--r--gcc_nrf52-mcuboot.ld10
-rw-r--r--gcc_nrf52.ld11
-rw-r--r--src/BootErrors.h10
-rw-r--r--src/CMakeLists.txt23
-rw-r--r--src/components/alarm/AlarmController.cpp114
-rw-r--r--src/components/alarm/AlarmController.h68
-rw-r--r--src/components/battery/BatteryController.cpp37
-rw-r--r--src/components/battery/BatteryController.h18
-rw-r--r--src/components/ble/AlertNotificationClient.cpp14
-rw-r--r--src/components/ble/AlertNotificationService.cpp11
-rw-r--r--src/components/ble/BatteryInformationService.cpp6
-rw-r--r--src/components/ble/CurrentTimeClient.cpp4
-rw-r--r--src/components/ble/CurrentTimeService.cpp4
-rw-r--r--src/components/ble/DeviceInformationService.cpp14
-rw-r--r--src/components/ble/DfuService.cpp26
-rw-r--r--src/components/ble/HeartRateService.cpp4
-rw-r--r--src/components/ble/ImmediateAlertService.cpp6
-rw-r--r--src/components/ble/NavigationService.cpp77
-rw-r--r--src/components/ble/NavigationService.h17
-rw-r--r--src/components/ble/NimbleController.cpp125
-rw-r--r--src/components/ble/NimbleController.h7
-rw-r--r--src/components/ble/NotificationManager.cpp8
-rw-r--r--src/components/ble/NotificationManager.h5
-rw-r--r--src/components/brightness/BrightnessController.cpp32
-rw-r--r--src/components/brightness/BrightnessController.h3
-rw-r--r--src/components/datetime/DateTimeController.cpp51
-rw-r--r--src/components/datetime/DateTimeController.h17
-rw-r--r--src/components/fs/FS.h2
-rw-r--r--src/components/motor/MotorController.cpp21
-rw-r--r--src/components/motor/MotorController.h7
-rw-r--r--src/components/settings/Settings.h59
-rw-r--r--src/displayapp/Apps.h7
-rw-r--r--src/displayapp/Colors.cpp27
-rw-r--r--src/displayapp/Colors.h10
-rw-r--r--src/displayapp/DisplayApp.cpp77
-rw-r--r--src/displayapp/DisplayApp.h11
-rw-r--r--src/displayapp/DisplayAppRecovery.cpp2
-rw-r--r--src/displayapp/DisplayAppRecovery.h34
-rw-r--r--src/displayapp/Messages.h4
-rw-r--r--src/displayapp/screens/Alarm.cpp265
-rw-r--r--src/displayapp/screens/Alarm.h56
-rw-r--r--src/displayapp/screens/ApplicationList.cpp8
-rw-r--r--src/displayapp/screens/ApplicationList.h3
-rw-r--r--src/displayapp/screens/BatteryInfo.cpp21
-rw-r--r--src/displayapp/screens/BatteryInfo.h6
-rw-r--r--src/displayapp/screens/Brightness.cpp4
-rw-r--r--src/displayapp/screens/Brightness.h3
-rw-r--r--src/displayapp/screens/Clock.cpp7
-rw-r--r--src/displayapp/screens/Clock.h2
-rw-r--r--src/displayapp/screens/Error.cpp50
-rw-r--r--src/displayapp/screens/Error.h21
-rw-r--r--src/displayapp/screens/FirmwareUpdate.cpp5
-rw-r--r--src/displayapp/screens/FirmwareUpdate.h3
-rw-r--r--src/displayapp/screens/FirmwareValidation.cpp4
-rw-r--r--src/displayapp/screens/FirmwareValidation.h2
-rw-r--r--src/displayapp/screens/FlashLight.cpp4
-rw-r--r--src/displayapp/screens/FlashLight.h2
-rw-r--r--src/displayapp/screens/HeartRate.cpp7
-rw-r--r--src/displayapp/screens/HeartRate.h4
-rw-r--r--src/displayapp/screens/InfiniPaint.cpp4
-rw-r--r--src/displayapp/screens/InfiniPaint.h2
-rw-r--r--src/displayapp/screens/Label.cpp4
-rw-r--r--src/displayapp/screens/Label.h2
-rw-r--r--src/displayapp/screens/List.cpp5
-rw-r--r--src/displayapp/screens/List.h2
-rw-r--r--src/displayapp/screens/Meter.cpp8
-rw-r--r--src/displayapp/screens/Meter.h4
-rw-r--r--src/displayapp/screens/Metronome.cpp8
-rw-r--r--src/displayapp/screens/Metronome.h4
-rw-r--r--src/displayapp/screens/Motion.cpp7
-rw-r--r--src/displayapp/screens/Motion.h3
-rw-r--r--src/displayapp/screens/Music.cpp7
-rw-r--r--src/displayapp/screens/Music.h4
-rw-r--r--src/displayapp/screens/Navigation.cpp9
-rw-r--r--src/displayapp/screens/Navigation.h4
-rw-r--r--src/displayapp/screens/Notifications.cpp12
-rw-r--r--src/displayapp/screens/Notifications.h12
-rw-r--r--src/displayapp/screens/Paddle.cpp10
-rw-r--r--src/displayapp/screens/Paddle.h4
-rw-r--r--src/displayapp/screens/PineTimeStyle.cpp71
-rw-r--r--src/displayapp/screens/PineTimeStyle.h8
-rw-r--r--src/displayapp/screens/Screen.cpp6
-rw-r--r--src/displayapp/screens/Screen.h24
-rw-r--r--src/displayapp/screens/ScreenList.h5
-rw-r--r--src/displayapp/screens/Steps.cpp8
-rw-r--r--src/displayapp/screens/Steps.h25
-rw-r--r--src/displayapp/screens/StopWatch.cpp12
-rw-r--r--src/displayapp/screens/StopWatch.h5
-rw-r--r--src/displayapp/screens/SystemInfo.cpp22
-rw-r--r--src/displayapp/screens/SystemInfo.h5
-rw-r--r--src/displayapp/screens/Tile.cpp4
-rw-r--r--src/displayapp/screens/Tile.h1
-rw-r--r--src/displayapp/screens/Timer.cpp46
-rw-r--r--src/displayapp/screens/Timer.h35
-rw-r--r--src/displayapp/screens/Twos.cpp6
-rw-r--r--src/displayapp/screens/Twos.h3
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.cpp36
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.h6
-rw-r--r--src/displayapp/screens/WatchFaceDigital.cpp20
-rw-r--r--src/displayapp/screens/WatchFaceDigital.h5
-rw-r--r--src/displayapp/screens/settings/QuickSettings.cpp10
-rw-r--r--src/displayapp/screens/settings/QuickSettings.h2
-rw-r--r--src/displayapp/screens/settings/SettingDisplay.cpp4
-rw-r--r--src/displayapp/screens/settings/SettingDisplay.h1
-rw-r--r--src/displayapp/screens/settings/SettingPineTimeStyle.cpp318
-rw-r--r--src/displayapp/screens/settings/SettingPineTimeStyle.h56
-rw-r--r--src/displayapp/screens/settings/SettingSetDate.cpp198
-rw-r--r--src/displayapp/screens/settings/SettingSetDate.h41
-rw-r--r--src/displayapp/screens/settings/SettingSetTime.cpp154
-rw-r--r--src/displayapp/screens/settings/SettingSetTime.h33
-rw-r--r--src/displayapp/screens/settings/SettingSteps.cpp7
-rw-r--r--src/displayapp/screens/settings/SettingSteps.h23
-rw-r--r--src/displayapp/screens/settings/SettingTimeFormat.cpp6
-rw-r--r--src/displayapp/screens/settings/SettingTimeFormat.h1
-rw-r--r--src/displayapp/screens/settings/SettingWakeUp.cpp4
-rw-r--r--src/displayapp/screens/settings/SettingWakeUp.h1
-rw-r--r--src/displayapp/screens/settings/SettingWatchFace.cpp4
-rw-r--r--src/displayapp/screens/settings/SettingWatchFace.h1
-rw-r--r--src/displayapp/screens/settings/Settings.cpp28
-rw-r--r--src/displayapp/screens/settings/Settings.h5
-rw-r--r--src/drivers/Cst816s.cpp49
-rw-r--r--src/drivers/Cst816s.h19
-rw-r--r--src/drivers/PinMap.h38
-rw-r--r--src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h2
-rw-r--r--src/main.cpp72
-rw-r--r--src/recoveryLoader.cpp19
-rw-r--r--src/systemtask/Messages.h6
-rw-r--r--src/systemtask/SystemTask.cpp116
-rw-r--r--src/systemtask/SystemTask.h18
148 files changed, 2751 insertions, 891 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml
new file mode 100644
index 00000000..efcba56c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.yaml
@@ -0,0 +1,59 @@
+name: Bug Report
+description: File a bug report
+title: "[Bug]: "
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Thanks for taking the time to fill out this bug report!**
+ *Please, before opening a bug report, check if similar issues already exist. In that case, use those issues to provide your feedback instead.*
+ - type: checkboxes
+ attributes:
+ options:
+ - label: I searched for similar bug reports and found none was relevant.
+ required: true
+ - type: input
+ id: desc-brief
+ attributes:
+ label: What happened?
+ description: A one-line description of the bug.
+ placeholder: "Ex. I woke up as a Kafkian insect this morning."
+ validations:
+ required: true
+ - type: input
+ id: desc-expected
+ attributes:
+ label: What should happen instead?
+ description: The behaviour you were expecting to see.
+ placeholder: "Ex. I was expecting to wake up as a human."
+ - type: textarea
+ id: desc-steps
+ attributes:
+ label: Reproduction steps
+ description: "How do you trigger this bug? Please walk us through it step by step."
+ validations:
+ required: true
+ - type: textarea
+ id: desc-long
+ attributes:
+ label: More details?
+ description: Give us more details about the bug and any personal attempts you made to fix it.
+ placeholder: Tell us more!
+ - type: input
+ id: version
+ attributes:
+ label: Version
+ description: |
+ What [version of the firmware](https://github.com/JF002/InfiniTime/blob/develop/doc/gettingStarted/gettingStarted-1.0.md#how-to-check-the-version-of-infinitime-and-the-bootloader) are you running?
+ If you are running an older version, please consider [updating to the latest firmware](https://github.com/JF002/InfiniTime/blob/develop/doc/gettingStarted/gettingStarted-1.0.md#how-to-update-your-pinetime).
+ If you are running directly from git, specify the branch or the commit hash directly.
+ placeholder: "Ex. v1.6.0 or develop or fc922b60"
+ validations:
+ required: true
+ - type: input
+ id: companion-app
+ attributes:
+ label: Companion app
+ description: Which companion app are you using (if relevant)?
+ placeholder: "Ex. Gadgetbridge v0.60.0, Siglo v0.9.4"
diff --git a/.github/ISSUE_TEMPLATE/feature-request.yaml b/.github/ISSUE_TEMPLATE/feature-request.yaml
new file mode 100644
index 00000000..092ef909
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.yaml
@@ -0,0 +1,41 @@
+name: Feature Request
+description: File a feature request
+title: ""
+labels: ["feature request"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Thanks for taking the time to fill out this feature request!**
+ *Please, before opening a feature request, check if similar issues already exist. In that case, use those issues to provide your feedback instead.*
+ - type: checkboxes
+ attributes:
+ options:
+ - label: I searched for similar feature request and found none was relevant.
+ required: true
+ - type: markdown
+ attributes:
+ value: |
+ **Note:** keep in mind that, while InfiniTime is usable, it is still under heavy development and as such it is continuously evolving.
+ Some features you want to see implemented might not be compatible with the current state of the project, or might not even be suitable to include *in the firmware* of the watch.
+ - type: input
+ id: desc-brief
+ attributes:
+ label: Pitch us your idea!
+ description: A one-line elevator pitch of the feature you'd like to see implemented.
+ placeholder: "Ex. My dog wants InfiniTime on its smart collar."
+ validations:
+ required: true
+ - type: textarea
+ id: desc-long
+ attributes:
+ label: Description
+ description: |
+ Give us a detailed description of the feature you are proposing. Mockups or a description of the possible use cases are highly appreciated.
+ Tell us why this should be included in the firmware.
+ placeholder: "Ex. Here is a drawing of my dog wearing an InfiniTime collar and smiling."
+ - type: markdown
+ id: companion-app
+ attributes:
+ value: |
+ If this requires features missing from other software (for example a companion app), please take care of opening any relevant feature request over there as well.
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 4a71b7e0..bd24359a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -9,13 +9,13 @@ name: Build PineTime Firmware
# When to run this Workflow...
on:
- # Run this Workflow when files are updated (Pushed) in the "master" Branch
+ # Run this Workflow when files are updated (Pushed) in the "master" and "develop" Branch
push:
- branches: [ master ]
+ branches: [ master, develop ]
- # Also run this Workflow when a Pull Request is created or updated in the "master" Branch
+ # Also run this Workflow when a Pull Request is created or updated in the "master" and "develop" Branch
pull_request:
- branches: [ master ]
+ branches: [ master, develop ]
# Steps to run for the Workflow
jobs:
@@ -44,7 +44,7 @@ jobs:
- name: Install Embedded Arm Toolchain arm-none-eabi-gcc
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:
# GNU Embedded Toolchain for Arm release name, in the V-YYYY-qZ format (e.g. "9-2019-q4")
release: 9-2020-q2
@@ -83,10 +83,11 @@ jobs:
if: steps.cache-mcuboot.outputs.cache-hit != 'true' # Install MCUBoot if not found in cache
run: |
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
- 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
run: |
@@ -99,6 +100,8 @@ jobs:
- name: Checkout source files
uses: actions/checkout@v2
+ with:
+ submodules: recursive
- name: Show files
run: set ; pwd ; ls -l
@@ -110,7 +113,7 @@ jobs:
run: |
mkdir -p 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
@@ -125,19 +128,10 @@ jobs:
cd build
make pinetime-mcuboot-app
- - name: Create firmware image
- 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
+ - name: Unzip 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 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
uses: actions/upload-artifact@v2
diff --git a/.gitignore b/.gitignore
index 6de76a9e..39fb672b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,4 +38,8 @@ Testing/Temporary/
**/.DS_Store
# Windows
-**/thumbs.db \ No newline at end of file
+**/thumbs.db
+
+#VSCODE
+.vscode/.cortex-debug.registers.state.json
+.vscode/.cortex-debug.peripherals.state.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8f0e63f4..f1cc3a81 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,5 +5,55 @@
"-DNRF5_SDK_PATH=${env:NRF5_SDK_PATH}",
],
"cmake.generator": "Unix Makefiles",
- "clang-tidy.buildPath": "build/compile_commands.json"
+ "clang-tidy.buildPath": "build/compile_commands.json",
+ "files.associations": {
+ "array": "cpp",
+ "atomic": "cpp",
+ "bit": "cpp",
+ "*.tcc": "cpp",
+ "bitset": "cpp",
+ "cctype": "cpp",
+ "chrono": "cpp",
+ "clocale": "cpp",
+ "cmath": "cpp",
+ "cstdarg": "cpp",
+ "cstddef": "cpp",
+ "cstdint": "cpp",
+ "cstdio": "cpp",
+ "cstdlib": "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",
+ "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",
+ "istream": "cpp",
+ "limits": "cpp",
+ "new": "cpp",
+ "ostream": "cpp",
+ "sstream": "cpp",
+ "stdexcept": "cpp",
+ "streambuf": "cpp",
+ "cinttypes": "cpp",
+ "typeinfo": "cpp"
+ }
}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b442fc11..a8ecb81f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
-project(pinetime VERSION 1.3.0 LANGUAGES C CXX ASM)
+project(pinetime VERSION 1.6.0 LANGUAGES C CXX ASM)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
@@ -51,6 +51,14 @@ if(BUILD_DFU)
set(BUILD_DFU true)
endif()
+option(WATCH_COLMI_P8 "Build for the Colmi P8" OFF)
+set(TARGET_DEVICE "PineTime")
+
+if(WATCH_COLMI_P8)
+ set(TARGET_DEVICE "Colmi P8")
+ add_definitions(-DWATCH_P8)
+endif()
+
set(PROJECT_GIT_COMMIT_HASH "")
execute_process(COMMAND git rev-parse --short HEAD
@@ -68,6 +76,7 @@ message(" * Version : " ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${P
message(" * Toolchain : " ${ARM_NONE_EABI_TOOLCHAIN_PATH})
message(" * GitRef(S) : " ${PROJECT_GIT_COMMIT_HASH})
message(" * NRF52 SDK : " ${NRF5_SDK_PATH})
+message(" * Target device : " ${TARGET_DEVICE})
set(PROGRAMMER "???")
if(USE_JLINK)
message(" * Programmer/debugger : JLINK")
diff --git a/README.md b/README.md
index 6549ece9..6719aa3e 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,10 @@
-# PineTime
-
-[![Build PineTime Firmware](https://github.com/JF002/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/JF002/InfiniTime/actions)
-
-> The PineTime is a free and open source smartwatch capable of running custom-built open operating systems. Some of the notable features include a heart rate monitor, a week-long battery as well as a capacitive touch IPS display that is legible in direct sunlight. It is a fully community driven side-project, which means that it will ultimately be up to the developers and end-users to determine when they deem the PineTime ready to ship.
-
-> We envision the PineTime as a companion for not only your PinePhone but also for your favorite devices — any phone, tablet, or even PC.
-
-*https://www.pine64.org/pinetime/*
-
-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
+[![Build PineTime Firmware](https://github.com/InfiniTimeOrg/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/InfiniTimeOrg/InfiniTime/actions)
+
![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](https://www.pine64.org/pinetime/) :
- Code written in **modern C++**;
- Build system based on **CMake**;
@@ -22,6 +12,11 @@ The goal of this project is to design an open-source firmware for the Pinetime s
- Using **[LittleVGL/LVGL 7](https://lvgl.io/)** as UI library...
- ... and **[NimBLE 1.3.0](https://github.com/apache/mynewt-nimble)** as BLE stack.
+## New to InfiniTime?
+
+ - [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)
+
## Overview
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
@@ -70,18 +65,15 @@ As of now, here is the list of achievements of this project:
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
+ * **[Experimental]** [Infini-iOS](https://github.com/xan-m/Infini-iOS) (on iOS)
- OTA (Over-the-air) update via BLE
- - [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
+ - [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://www.mcuboot.com)
## Documentation
-### Getting started
-
- - [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)
-
### Develop
-
+ - [Rough structure of the code](doc/code/Intro.md)
+ - [How to implement an application](doc/code/Apps.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)
diff --git a/cmake-nRF5x/readme.md b/cmake-nRF5x/readme.md
index 2ce76892..0127a2e6 100755
--- a/cmake-nRF5x/readme.md
+++ b/cmake-nRF5x/readme.md
@@ -98,7 +98,7 @@ The script makes use of the following tools:
After setup you can use cmake as usual:
-1. Generate the actual build files (out-of-source builds are strongly recomended):
+1. Generate the actual build files (out-of-source builds are strongly recommended):
```commandline
cmake -H. -B"cmake-build" -G "Unix Makefiles"
diff --git a/doc/MemoryAnalysis.md b/doc/MemoryAnalysis.md
index 3251c98d..7304e3f3 100644
--- a/doc/MemoryAnalysis.md
+++ b/doc/MemoryAnalysis.md
@@ -6,7 +6,7 @@ The PineTime is equipped with the following memories:
Note that the NRF52832 cannot execute code stored in the external flash : we need to store the whole firmware in the internal flash memory, and use the external one to store graphicals assets, fonts...
-This document describes how the RAM and Flash memories are used in InfiniTime and how to analyze and monitor their usage. It was written in the context of [this memory analysis effort](https://github.com/JF002/InfiniTime/issues/313).
+This document describes how the RAM and Flash memories are used in InfiniTime and how to analyze and monitor their usage. It was written in the context of [this memory analysis effort](https://github.com/InfiniTimeOrg/InfiniTime/issues/313).
## Code sections
A binary is composed of multiple sections. Most of the time, these sections are : .text, .rodata, .data and .bss but more sections can be defined in the linker script.
@@ -38,7 +38,7 @@ In this analysis, I used [Linkermapviz](https://github.com/PromyLOPh/linkermapvi
Using this tool, you can easily see the size of each symbol relative to the other one, and check what is using most of the space,...
-Also, as Linkermapviz is written in Python, you can easily modify it to adapt it to your firmware, export data in another format,... For example, [I modified it to parse the contents of the MAP file and export it in a CSV file](https://github.com/JF002/InfiniTime/issues/313#issuecomment-842338620). I could later on open this file in LibreOffice Calc and use sort/filter functionality to search for specific symbols in specific files...
+Also, as Linkermapviz is written in Python, you can easily modify it to adapt it to your firmware, export data in another format,... For example, [I modified it to parse the contents of the MAP file and export it in a CSV file](https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620). I could later on open this file in LibreOffice Calc and use sort/filter functionality to search for specific symbols in specific files...
### Puncover
[Puncover](https://github.com/HBehrens/puncover) is another useful tools that analyses the binary file generated by the compiler (the .out file that contains all debug information). It provides valuable information about the symbols (data and code): name, position, size, max stack of each functions, callers, callees...
@@ -69,8 +69,8 @@ This way, you can easily check what needs to be optimized : we should find a way
It's always a good idea to check the flash memory space when working on the project : this way, you can easily check that your developments are using a reasonable amount of space.
### Links
- - Analysis with linkermapviz : https://github.com/JF002/InfiniTime/issues/313#issuecomment-842338620
- - Analysis with Puncover : https://github.com/JF002/InfiniTime/issues/313#issuecomment-847311392
+ - Analysis with linkermapviz : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620
+ - Analysis with Puncover : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-847311392
## RAM
RAM memory contains all the data that can be modified at run-time: variables, stack, heap...
@@ -93,7 +93,7 @@ int main() {
In Infinitime 1.1, the biggest buffers are the buffers allocated for LVGL (14KB) and the one for FreeRTOS (16KB). Nimble also allocated 9KB of RAM.
### Stack
-The stack will be used for everything except tasks, which have their own stack allocated by FreeRTOS. The stack is 8192B and is allocated in the [linker script](https://github.com/JF002/InfiniTime/blob/develop/nrf_common.ld#L148).
+The stack will be used for everything except tasks, which have their own stack allocated by FreeRTOS. The stack is 8192B and is allocated in the [linker script](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/nrf_common.ld#L148).
An easy way to monitor its usage is by filling the section with a known pattern at boot time, then use the firmware and dump the memory. You can then check the maximum stack usage by checking the address from the beginning of the stack that were overwritten.
#### Fill the stack section by a known pattern:
@@ -197,10 +197,10 @@ On the following dump, the maximum stack usage is 520 bytes (0xFFFF - 0xFDF8):
According to my experimentations, we don't use the stack that much, and 8192 bytes is probably way too big for InfiniTime!
#### Links
- - https://github.com/JF002/InfiniTime/issues/313#issuecomment-851035070
+ - https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035070
### Heap
-The heap is declared in the [linker script](https://github.com/JF002/InfiniTime/blob/develop/nrf_common.ld#L136) and its current size is 8192 bytes. The heap is used for dynamic memory allocation(`malloc()`, `new`...).
+The heap is declared in the [linker script](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/nrf_common.ld#L136) and its current size is 8192 bytes. The heap is used for dynamic memory allocation(`malloc()`, `new`...).
Heap monitoring is not easy, but it seems that we can use the following code to know the current usage of the heap:
@@ -239,7 +239,7 @@ Using this technique, I was able to trace all malloc calls at boot (boot -> digi
- hr task = 304
#### Links
- - https://github.com/JF002/InfiniTime/issues/313#issuecomment-851035625
+ - https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035625
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-1-calculating-stack-size/
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-2-properly-allocating-stacks/
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-3-avoiding-heap-errors/
@@ -263,7 +263,7 @@ For example a simple lv_label needs **~140 bytes** of memory.
I tried to monitor this max value while going through all the apps of InfiniTime 1.1 : the max value I've seen is **5660 bytes**. It means that we could probably **reduce the size of the buffer from 14KB to 6 - 10 KB** (we have to take the fragmentation of the memory into account).
### Links
- - https://github.com/JF002/InfiniTime/issues/313#issuecomment-850890064
+ - https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-850890064
## FreeRTOS heap and task stack
diff --git a/doc/NavigationService.md b/doc/NavigationService.md
index d0899817..fd81d0bf 100644
--- a/doc/NavigationService.md
+++ b/doc/NavigationService.md
@@ -9,19 +9,19 @@ manDist (string) - Manouvre Distance, the distance to the upcoming change
progress (uint8) - Percent complete of total route, value 0-100
## Service
-The service UUID is c7e60001-78fc-48fe-8e23-433b3a1942d0
+The service UUID is 00010000-78fc-48fe-8e23-433b3a1942d0
## Characteristics
-## Flags (UUID c7e60002-78fc-48fe-8e23-433b3a1942d0)
+## Flags (UUID 00010001-78fc-48fe-8e23-433b3a1942d0)
All included icons are from pure-maps, which provides the actual routing from the client. The icon names ultimately come from the mapbox project "direction-icons", See https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation See the end of this document for the full lsit of supported icon names.
-## Narrative (UUID c7e60003-78fc-48fe-8e23-433b3a1942d0)
+## Narrative (UUID 00010002-78fc-48fe-8e23-433b3a1942d0)
This is a client supplied string describing the upcoming instruction such as "At the roundabout take the first exit".
-## Man Dist (UUID c7e60004-78fc-48fe-8e23-433b3a1942d0)
+## Man Dist (UUID 00010003-78fc-48fe-8e23-433b3a1942d0)
This is a short string describing the distance to the upcoming instruction such as "50 m".
-## Progress (UUID c7e60001=5-78fc-48fe-8e23-433b3a1942d0)
+## Progress (UUID 00010004-78fc-48fe-8e23-433b3a1942d0)
The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
## Full icon list
diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md
index 87b6dd9a..feae8d76 100644
--- a/doc/buildAndProgram.md
+++ b/doc/buildAndProgram.md
@@ -9,7 +9,7 @@ To build this project, you'll need:
## Build steps
### Clone the repo
```
-git clone https://github.com/JF002/InfiniTime.git
+git clone https://github.com/InfiniTimeOrg/InfiniTime.git
cd InfiniTime
git submodule update --init
mkdir build
@@ -28,11 +28,12 @@ CMake configures the project according to variables you specify the command line
**GDB_CLIENT_BIN_PATH**|Path to arm-none-eabi-gdb executable. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_BIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb`
**GDB_CLIENT_TARGET_REMOTE**|Target remote connection string. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_TARGET_REMOTE=/dev/ttyACM0`
**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1`
+**WATCH_COLMI_P8**|Use pin configuration for Colmi P8 watch|`-DWATCH_COLMI_P8=1`
####(**) Note about **CMAKE_BUILD_TYPE**:
-By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/JF002/InfiniTime/releases) new versions of InfiniTime.
+By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/InfiniTimeOrg/InfiniTime/releases) new versions of InfiniTime.
-The *Debug* mode disables all optimizations, which makes the code easier to debug. However, the binary size will likely be too big to fit in the internal flash memory. If you want to build and debug a *Debug* binary, you'll need to disable some parts of the code. For example, the icons for the **Navigation** app use a lot of memory space. You can comment the content of `m_iconMap` in the [Navigation](https://github.com/JF002/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory.
+The *Debug* mode disables all optimizations, which makes the code easier to debug. However, the binary size will likely be too big to fit in the internal flash memory. If you want to build and debug a *Debug* binary, you'll need to disable some parts of the code. For example, the icons for the **Navigation** app use a lot of memory space. You can comment the content of `m_iconMap` in the [Navigation](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory.
####(**) Note about **BUILD_DFU**:
DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mecanism. To generate the DFU file, the Python tool [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) is needed on your system. Check that this tool is properly installed before enabling this option.
diff --git a/doc/buildWithVScode.md b/doc/buildWithVScode.md
index c1df17b7..23c97145 100644
--- a/doc/buildWithVScode.md
+++ b/doc/buildWithVScode.md
@@ -36,7 +36,17 @@ Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemNam
More documentation is available in the [readme in .devcontainer](.devcontainer/readme.md)
-
+### DevContainer on Ubuntu
+To use the DevContainer configuration on Ubuntu based systems two changes need to be made:
+
+1. Modify the file ``.devcontainer/devcontainer.json`` and add the argument ``"--net=host"`` to the ``"runArgs"`` parameter making the line look like this:
+`` "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", "--net=host"],
+``
+2. Modify the file ``.vscode/launch.json`` and change the argument of ``"gdbTarget"`` to ``"127.0.0.1:3333"``, making the line look like:
+``"gdbTarget": "127.0.0.1:3333",``
+3. To start debugging launch openocd on your host system with the appropriate configuration, for example with a stlink-v2 the command is:
+``openocd -f interface/stlink.cfg -f target/nrf52.cfg``. This launches openocd with the default ports ``3333``, ``4444`` and ``6666``.
+4. In VsCode go to the Debug pane on the left of the screen and select the configuration ``Debug - Openocd docker Remote`` and hit the play button on the left.
diff --git a/doc/code/Apps.md b/doc/code/Apps.md
new file mode 100644
index 00000000..b3bab042
--- /dev/null
+++ b/doc/code/Apps.md
@@ -0,0 +1,106 @@
+# Apps
+This page will teach you:
+- what apps in InfiniTime are
+- how to implement your own app
+
+## Theory
+Apps are the things you can launch from the app selection you get by swiping up.
+At the moment, settings and even the app launcher itself or the clock are implemented very similarly, this might change in the future though.
+Every app in InfiniTime is it's own class.
+An instance of the class is created when the app is launched and destroyed when the user exits the app.
+They run inside the "displayapp" task (briefly discussed [here](./Intro.md)).
+Apps are responsible for everything drawn on the screen when they are running.
+By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected.
+
+## Interface
+Every app class has to be inside the namespace `Pinetime::Applications::Screens` and inherit from `Screen`.
+The constructor should have at least one parameter `DisplayApp* app`, which it needs for the constructor of its parent class Screen.
+Other parameters should be references to controllers that the app needs.
+A destructor is needed to clean up LVGL and restore any changes (for example re-enable sleeping).
+App classes can override `bool OnButtonPushed()`, `bool OnTouchEvent(TouchEvents event)` and `bool OnTouchEvent(uint16_t x, uint16_t y)` to implement their own functionality for those events.
+If an app only needs to display some text and do something upon a touch screen button press,
+it does not need to override any of these functions, as LVGL can also handle touch events for you.
+If you have any doubts, you can always look at how the other apps are doing things.
+
+### Continuous updating
+If your app needs to be updated continuously, yo can do so by overriding the `Refresh()` function in your class
+and calling `lv_task_create` inside the constructor.
+An example call could look like this: <br>
+`taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);` <br>
+With `taskRefresh` being a member variable of your class and of type `lv_task_t*`.
+Remember to delete the task again using `lv_task_del`.
+The function `RefreshTaskCallback` is inherited from screen and just calls your `Refresh` function.
+
+### Apps with multiple screens
+InfiniTime provides a mini-library in [displayapp/screens/ScreenList.h](/src/displayapp/screens/ScreenList.h)
+which makes it relatively easy to add multiple screens to your app.
+To use it, #include it in the header file of your app and add a ScreenList member to your class.
+The template argument should be the number of screens you need.
+You will also need to add `CreateScreen` functions that return `std::unique_ptr<Screen>`
+to your class, one for every screen you have.
+There are still some things left to to that I won't cover here.
+To figure them out, have a look at the "apps" ApplicationList, Settings and SystemInfo.
+
+
+## Creating your own app
+A minimal app could look like this: <br>
+MyApp.h:
+```cpp
+#pragma once
+
+#include "displayapp/screens/Screen.h"
+#include <lvgl/lvgl.h>
+
+namespace PineTime {
+ namespace Applications {
+ namespace Screens {
+ class MyApp : public Screen {
+ public:
+ MyApp(DisplayApp* app);
+ ~MyApp() override;
+ }
+ }
+ }
+}
+```
+
+MyApp.cpp:
+```cpp
+#include "MyApp.h"
+#include "displayapp/DisplayApp.h"
+
+using namespace Pinetime::Applications::Screens;
+
+MyApp::MyApp(DisplayApp* app) : Screen(app) {
+ lv_obj_t* title = lv_label_create(lv_scr_act(), NULL);
+ lv_label_set_text_static(title, "My test application");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+}
+
+MyApp::~MyApp() {
+ lv_obj_clean(lv_scr_act());
+}
+```
+Both of these files should be in [displayapp/screens/](/src/displayapp/screens/)
+or [displayapp/screens/settings/](/src/displayapp/screens/settings/) if it's a setting app.
+
+Now we have our very own app, but InfiniTime does not know about it yet.
+The first step is to include your MyApp.cpp (or any new cpp files for that matter)
+in the compilation by adding it to [CMakeLists.txt](/CMakeLists.txt).
+The next step to making it launchable is to give your app an id.
+To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/Apps.h](/src/displayapp/Apps.h)).
+Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
+Now, go to the function `DisplayApp::LoadApp` and add another case to the switch statement.
+The case will be the id you gave your app earlier.
+If your app needs any additional arguments, this is the place to pass them.
+
+If you want your app to be launched from the regular app launcher, go to [displayapp/screens/ApplicationList.cpp](/src/displayapp/screens/ApplicationList.cpp).
+Add your app to one of the `CreateScreen` functions, or add another `CreateScreen` function if there are no empty spaces for your app. <br>
+If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.cpp](/src/displayapp/screens/settings/Settings.cpp).
+
+You should now be able to [build](../buildAndProgram.md) the firmware
+and flash it to your PineTime. Yay!
+
+Please remember to pay attention to the [UI guidelines](../ui_guidelines.md)
+when designing an app that you want to include in mainstream InfiniTime.
diff --git a/doc/code/Intro.md b/doc/code/Intro.md
new file mode 100644
index 00000000..762102fe
--- /dev/null
+++ b/doc/code/Intro.md
@@ -0,0 +1,42 @@
+# Introduction to the code
+This page is meant to guide you through the source code, so you can find the relevant files for what you're working on.
+
+## FreeRTOS
+Infinitime is based on FreeRTOS, a real-time operating system.
+FreeRTOS provides several quality of life abstractions (for example easy software timers)
+and most importantly supports multiple tasks.
+If you want to read up on real-time operating systems, you can look [here](https://www.freertos.org/implementation/a00002.html) and [here](https://www.freertos.org/features.html).
+The main "process" creates at least one task and then starts the FreeRTOS task scheduler.
+This main "process" is the standard main() function inside [main.cpp](/src/main.cpp).
+The task scheduler is responsible for giving every task enough cpu time.
+As there is only one core on the SoC of the PineTime, real concurrency is impossible and the scheduler has to swap tasks in and out to emulate it.
+
+### Tasks
+Tasks are created by calling `xTaskCreate` and passing a function with the signature `void functionName(void*)`.
+For more info on task creation see the [FreeRTOS Documentation](https://www.freertos.org/a00125.html).
+In our case, main calls `systemTask.Start()`, which creates the **"MAIN" task**.
+The function running inside that task is `SystemTask::Work()`.
+You may also see this task being referred to as the **work task**.
+Both functions are located inside [systemtask/SystemTask.cpp](/src/systemtask/SystemTask.cpp). `SystemTask::Work()` initializes all the driver and controller objects.
+It also starts the **task "displayapp"**, which is responsible for launching and running apps, controlling the screen and handling touch events (or forwarding them to the active app).
+You can find the "displayapp" task inside [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
+There are also other tasks that are responsible for Bluetooth ("ll" and "ble" inside [libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c](/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c))
+and periodic tasks like heartrate measurements ([heartratetask/HeartRateTask.cpp](/src/heartratetask/HeartRateTask.cpp)). <br>
+While it is possible for you to create your own task when you need it, it is recommended to just add functionality to `SystemTask::Work()` if possible.
+If you absolutely need to create another task, try to guess how much [stack space](https://www.freertos.org/FAQMem.html#StackSize) (in words/4-byte packets)
+it will need instead of just typing in a large-ish number.
+You can use the define `configMINIMAL_STACK_SIZE` which is currently set to 120 words.
+
+## Controllers
+Controllers in InfiniTime are singleton objects that can provide access to certain resources to apps.
+Some of them interface with drivers, others are the driver for the resource.
+The resources provided don't have to be hardware-based.
+They are declared in main.cpp and initialized in [systemtask/SystemTask.cpp](/src/systemtask/SystemTask.cpp).
+Some controllers can be passed by reference to apps that need access to the resource (for example vibration motor).
+They reside in [components/](/src/components/) inside their own subfolder.
+
+## Apps
+For more detail see the [Apps page](./Apps.md)
+
+## Bluetooth
+Header files with short documentation for the functions are inside [libs/mynewt-nimble/nimble/host/include/host/](/src/libs/mynewt-nimble/nimble/host/include/host/).
diff --git a/doc/contribute.md b/doc/contribute.md
index 0c34e2a5..21746433 100644
--- a/doc/contribute.md
+++ b/doc/contribute.md
@@ -2,7 +2,7 @@
## Report bugs
-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...
+Have you found a bug in the firmware? [Create an issue on Github](https://github.com/InfiniTimeOrg/InfiniTime/issues) explaining the bug, how to reproduce it, the version of the firmware you use...
## Write and improve documentation
@@ -18,18 +18,18 @@ You want to fix a bug, add a cool new functionality or improve the code? See *Ho
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
- - 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,...);
- - 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);
- - Clean your code and remove files that are not needed;
- - Write documentation related to your new feature if applicable;
- - 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;
+ - 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,...)
+ - 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)
+ - Clean your code and remove files that are not needed
+ - Write documentation related to your new feature if applicable
+ - 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
- Your PR will eventually be merged :)
Your contributions are more than welcome!
diff --git a/doc/filesInReleaseNotes.md b/doc/filesInReleaseNotes.md
index 1a37fefb..6a5873c0 100644
--- a/doc/filesInReleaseNotes.md
+++ b/doc/filesInReleaseNotes.md
@@ -1,9 +1,9 @@
# Using the releases
-For each new *stable* version of IniniTime, a [release note](https://github.com/JF002/InfiniTime/releases) is created. It contains a description of the main changes in the release and some files you can use to flash the firmware to your Pinetime.
+For each new *stable* version of IniniTime, a [release note](https://github.com/InfiniTimeOrg/InfiniTime/releases) is created. It contains a description of the main changes in the release and some files you can use to flash the firmware to your Pinetime.
This page describes the files from the release notes and how to use them.
-**NOTE :** the files included in different Releases could be different. This page describes the release notes of [version 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1), which is the version that is pre-programmed for the last batches of pinetimes but will be replaced with [1.0.0](https://github.com/jF002/infiniTime/releases/tag/1.0.0) around june 2021.
+**NOTE :** the files included in different Releases could be different. This page describes the release notes of [version 0.7.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.7.1), which is the version that is pre-programmed for the last batches of pinetimes but will be replaced with [1.0.0](https://github.com/jF002/infiniTime/releases/tag/1.0.0) around june 2021.
## Files included in the release notes
diff --git a/doc/gettingStarted/gettingStarted-1.0.md b/doc/gettingStarted/gettingStarted-1.0.md
index 88ff2072..3f8f38f6 100644
--- a/doc/gettingStarted/gettingStarted-1.0.md
+++ b/doc/gettingStarted/gettingStarted-1.0.md
@@ -8,15 +8,15 @@ You might have already seen these words by reading the announcement, release not
Basically, a **firmware** is just a software running on the embedded hardware of a device, the PineTime in this case.
**InfiniTime** is based on 3 distinct **firmwares**:
- - **[InfiniTime](https://github.com/JF002/InfiniTime)** itself, this is the *application firmware* running on the PineTime. This is the main firmware which provides most of the functionalities you'll use on a daily basis : bluetooth low-energy (BLE) connectivity, applications, watchfaces,...
+ - **[InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)** itself, this is the *application firmware* running on the PineTime. This is the main firmware which provides most of the functionalities you'll use on a daily basis : bluetooth low-energy (BLE) connectivity, applications, watchfaces,...
- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying **updates** of the *application firmware*, reverting them in case of issues and load the recovery firmware when requested.
- - **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/JF002/InfiniTime/releases/tag/0.14.1).
+ - **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1).
**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?
-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/InfiniTimeOrg/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 successful OTA or a manual reset - long push on the button).
@@ -33,7 +33,7 @@ And for version >= 1.0 :
![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 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/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/InfiniTimeOrg/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).
@@ -56,9 +56,9 @@ If your PineTime is currently running InfiniTime 0.7.1 and the old bootloader, w
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):
- 1. Flash the latest version of InfiniTime. The file to upload is named **pinetime-mcuboot-app-dfu-x.y.z.zip**. Here is the link to [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip).
+ 1. Flash the latest version of InfiniTime. The file to upload is named **pinetime-mcuboot-app-dfu-x.y.z.zip**. Here is the link to [InfiniTime 1.0](https://github.com/InfiniTimeOrg/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip).
2. Update the bootloader by applying the OTA procedure with the file named [**reloader-mcuboot.zip** from the repo of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/download/1.0.0/reloader-mcuboot.zip).
- 3. Install the recovery firmware by applying the OTA procedure with the file named [**pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip** from the version 0.14.1 of InfiniTime](https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip).
+ 3. Install the recovery firmware by applying the OTA procedure with the file named [**pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip** from the version 0.14.1 of InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip).
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)
diff --git a/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md b/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md
index 1187a9b7..57d16218 100644
--- a/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md
+++ b/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md
@@ -8,7 +8,7 @@ If you just want to flash or upgrade InfiniTime on your PineTime, this page is f
- [How to flash InfiniTime using the SWD interface](#how-to-flash-infinitime-using-the-swd-interface)
## InfiniTime releases and versions
-All releases of InfiniTime are available on the [release page of the GitHub repo](https://github.com/JF002/InfiniTime/releases).
+All releases of InfiniTime are available on the [release page of the GitHub repo](https://github.com/InfiniTimeOrg/InfiniTime/releases).
Versions that are tagged as **RELEASE CANDIDATE** are pre-release versions, that are available for testing before actually releasing a new stable version. If you want to help us debug the project and provide stable versions to other user, you can use them. If you want stable and tested version, you should not flash these release candidate version.
@@ -47,6 +47,8 @@ Read carefully the warning and tap **Install**:
Wait for the transfer to finish. Your PineTime should reset and reboot with the new version of InfiniTime!
+Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
+
![Gadgetbridge 5](gadgetbridge5.jpg)
### Using NRFConnect
@@ -64,6 +66,8 @@ Select **Distribution packet (ZIP)**:
Browse to the DFU file you downloaded previously, the DFU transfer will start automatically. When the transfer is finished, your PineTime will reset and restart on the new version of InfiniTime!
+Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
+
![NRFConnect 3](nrfconnect3.jpg)
## How to flash InfiniTime using the SWD interface
@@ -88,6 +92,10 @@ If you are using OpenOCD with a STLinkV2, you can find more info [on this page](
### Using Gadgetbridge
Good news! Gadgetbridge **automatically** synchronizes the time when connecting to your PineTime!
+### Using any Chromium-based web browser
+You can use it from your PC, Mac, Android. Browsers now have BLE support.
+https://hubmartin.github.io/WebBLEWatch/
+
### Using NRFConnect
You must enable the **CTS** *GATT server* into NRFConnect so that InfiniTime can synchronize the time with your smartphone.
diff --git a/doc/versioning.md b/doc/versioning.md
index b08af714..48e05043 100644
--- a/doc/versioning.md
+++ b/doc/versioning.md
@@ -3,4 +3,4 @@ The versioning of this project is based on [Semantic versionning](https://semver
- The **patch** is incremented when we fix a bug on a **released** version (most of the time using a **hotfix** branch).
- The **minor** is incremented when we release a new version with new features. It corresponds to a merge of **develop** into **master**.
- - The **major** should be incremented when a breaking change is made to the application. We still have to define what is a breaking change in the context of this project. For now, I suggest that it stays **0** until we have a fully functionning firmware suited for the final user. \ No newline at end of file
+ - The **major** should be incremented when a breaking change is made to the application. We still have to define what is a breaking change in the context of this project. For now, I suggest that it stays **0** until we have a fully functioning firmware suited for the final user. \ No newline at end of file
diff --git a/gcc_nrf52-mcuboot.ld b/gcc_nrf52-mcuboot.ld
index 0746f491..81b318c5 100644
--- a/gcc_nrf52-mcuboot.ld
+++ b/gcc_nrf52-mcuboot.ld
@@ -6,12 +6,18 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08020, LENGTH = 0x78000
- RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
+ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
-}
+ .noinit(NOLOAD):
+ {
+ PROVIDE(__start_noinit_data = .);
+ *(.noinit)
+ PROVIDE(__stop_noinit_data = .);
+ } > RAM
+} INSERT AFTER .bss
SECTIONS
{
diff --git a/gcc_nrf52.ld b/gcc_nrf52.ld
index 98e133aa..f9bc5b68 100644
--- a/gcc_nrf52.ld
+++ b/gcc_nrf52.ld
@@ -6,12 +6,18 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000, LENGTH = 0x78000
- RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
+ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
-}
+ .noinit(NOLOAD):
+ {
+ PROVIDE(__start_noinit_data = .);
+ *(.noinit)
+ PROVIDE(__stop_noinit_data = .);
+ } > RAM
+} INSERT AFTER .bss
SECTIONS
{
@@ -44,6 +50,7 @@ SECTIONS
PROVIDE(__stop_log_filter_data = .);
} > RAM
+
} INSERT AFTER .data;
SECTIONS
diff --git a/src/BootErrors.h b/src/BootErrors.h
new file mode 100644
index 00000000..d00418cc
--- /dev/null
+++ b/src/BootErrors.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace Pinetime {
+ namespace System {
+ enum class BootErrors {
+ None,
+ TouchController,
+ };
+ }
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ae3cc3b1..07eabe11 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -92,6 +92,9 @@ set(SDK_SOURCE_FILES
set(TINYCRYPT_SRC
libs/mynewt-nimble/ext/tinycrypt/src/aes_encrypt.c
libs/mynewt-nimble/ext/tinycrypt/src/utils.c
+ libs/mynewt-nimble/ext/tinycrypt/src/cmac_mode.c
+ libs/mynewt-nimble/ext/tinycrypt/src/ecc.c
+ libs/mynewt-nimble/ext/tinycrypt/src/ecc_dh.c
)
set(NIMBLE_SRC
@@ -104,6 +107,10 @@ set(NIMBLE_SRC
libs/mynewt-nimble/nimble/host/src/ble_l2cap.c
libs/mynewt-nimble/nimble/host/src/ble_hs_mbuf.c
libs/mynewt-nimble/nimble/host/src/ble_sm.c
+ libs/mynewt-nimble/nimble/host/src/ble_sm_cmd.c
+ libs/mynewt-nimble/nimble/host/src/ble_sm_lgcy.c
+ libs/mynewt-nimble/nimble/host/src/ble_sm_alg.c
+ libs/mynewt-nimble/nimble/host/src/ble_sm_sc.c
libs/mynewt-nimble/nimble/host/src/ble_gap.c
libs/mynewt-nimble/nimble/host/src/ble_gatts.c
libs/mynewt-nimble/nimble/host/src/ble_gattc.c
@@ -127,10 +134,6 @@ set(NIMBLE_SRC
libs/mynewt-nimble/nimble/host/src/ble_hs_atomic.c
libs/mynewt-nimble/nimble/host/src/ble_hs_adv.c
libs/mynewt-nimble/nimble/host/src/ble_hs_flow.c
- libs/mynewt-nimble/nimble/host/src/ble_sm.c
- libs/mynewt-nimble/nimble/host/src/ble_sm_cmd.c
- libs/mynewt-nimble/nimble/host/src/ble_sm_lgcy.c
- libs/mynewt-nimble/nimble/host/src/ble_sm_alg.c
libs/mynewt-nimble/nimble/host/src/ble_hs_mqueue.c
libs/mynewt-nimble/nimble/host/src/ble_hs_stop.c
libs/mynewt-nimble/nimble/host/src/ble_hs_startup.c
@@ -418,6 +421,9 @@ list(APPEND SOURCE_FILES
displayapp/screens/BatteryInfo.cpp
displayapp/screens/Steps.cpp
displayapp/screens/Timer.cpp
+ displayapp/screens/Error.cpp
+ displayapp/screens/Alarm.cpp
+ displayapp/Colors.cpp
## Settings
displayapp/screens/settings/QuickSettings.cpp
@@ -427,6 +433,9 @@ list(APPEND SOURCE_FILES
displayapp/screens/settings/SettingWakeUp.cpp
displayapp/screens/settings/SettingDisplay.cpp
displayapp/screens/settings/SettingSteps.cpp
+ displayapp/screens/settings/SettingPineTimeStyle.cpp
+ displayapp/screens/settings/SettingSetDate.cpp
+ displayapp/screens/settings/SettingSetTime.cpp
## Watch faces
displayapp/icons/bg_clock.c
@@ -472,6 +481,7 @@ list(APPEND SOURCE_FILES
components/motor/MotorController.cpp
components/settings/Settings.cpp
components/timer/TimerController.cpp
+ components/alarm/AlarmController.cpp
components/fs/FS.cpp
drivers/Cst816s.cpp
FreeRTOS/port.c
@@ -538,6 +548,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/firmwarevalidator/FirmwareValidator.cpp
components/settings/Settings.cpp
components/timer/TimerController.cpp
+ components/alarm/AlarmController.cpp
drivers/Cst816s.cpp
FreeRTOS/port.c
FreeRTOS/port_cmsis_systick.c
@@ -610,6 +621,8 @@ set(INCLUDE_FILES
displayapp/screens/Metronome.h
displayapp/screens/Motion.h
displayapp/screens/Timer.h
+ displayapp/screens/Alarm.h
+ displayapp/Colors.h
drivers/St7789.h
drivers/SpiNorFlash.h
drivers/SpiMaster.h
@@ -618,6 +631,7 @@ set(INCLUDE_FILES
drivers/DebugPins.h
drivers/InternalFlash.h
drivers/Hrs3300.h
+ drivers/PinMap.h
drivers/Bma421.h
drivers/Bma421_C/bma4.c
drivers/Bma421_C/bma423.c
@@ -640,6 +654,7 @@ set(INCLUDE_FILES
components/ble/HeartRateService.h
components/settings/Settings.h
components/timer/TimerController.h
+ components/alarm/AlarmController.h
drivers/Cst816s.h
FreeRTOS/portmacro.h
FreeRTOS/portmacro_cmsis.h
diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp
new file mode 100644
index 00000000..67ca05a9
--- /dev/null
+++ b/src/components/alarm/AlarmController.cpp
@@ -0,0 +1,114 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "AlarmController.h"
+#include "systemtask/SystemTask.h"
+#include "app_timer.h"
+#include "task.h"
+#include <chrono>
+
+using namespace Pinetime::Controllers;
+using namespace std::chrono_literals;
+
+AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
+}
+
+APP_TIMER_DEF(alarmAppTimer);
+
+namespace {
+ void SetOffAlarm(void* p_context) {
+ auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(p_context);
+ if (controller != nullptr) {
+ controller->SetOffAlarmNow();
+ }
+ }
+}
+
+void AlarmController::Init(System::SystemTask* systemTask) {
+ app_timer_create(&alarmAppTimer, APP_TIMER_MODE_SINGLE_SHOT, SetOffAlarm);
+ this->systemTask = systemTask;
+}
+
+void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
+ hours = alarmHr;
+ minutes = alarmMin;
+}
+
+void AlarmController::ScheduleAlarm() {
+ // Determine the next time the alarm needs to go off and set the app_timer
+ app_timer_stop(alarmAppTimer);
+
+ auto now = dateTimeController.CurrentDateTime();
+ alarmTime = now;
+ time_t ttAlarmTime = std::chrono::system_clock::to_time_t(alarmTime);
+ tm* tmAlarmTime = std::localtime(&ttAlarmTime);
+
+ // If the time being set has already passed today,the alarm should be set for tomorrow
+ if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) {
+ tmAlarmTime->tm_mday += 1;
+ // tm_wday doesn't update automatically
+ tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7;
+ }
+
+ tmAlarmTime->tm_hour = hours;
+ tmAlarmTime->tm_min = minutes;
+ tmAlarmTime->tm_sec = 0;
+
+ // if alarm is in weekday-only mode, make sure it shifts to the next weekday
+ if (recurrence == RecurType::Weekdays) {
+ if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day
+ tmAlarmTime->tm_mday += 1;
+ } else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days
+ tmAlarmTime->tm_mday += 2;
+ }
+ }
+ tmAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST
+
+ // now can convert back to a time_point
+ alarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmAlarmTime));
+ auto mSecToAlarm = std::chrono::duration_cast<std::chrono::milliseconds>(alarmTime - now).count();
+ app_timer_start(alarmAppTimer, APP_TIMER_TICKS(mSecToAlarm), this);
+
+ state = AlarmState::Set;
+}
+
+uint32_t AlarmController::SecondsToAlarm() {
+ return std::chrono::duration_cast<std::chrono::seconds>(alarmTime - dateTimeController.CurrentDateTime()).count();
+}
+
+void AlarmController::DisableAlarm() {
+ app_timer_stop(alarmAppTimer);
+ state = AlarmState::Not_Set;
+}
+
+void AlarmController::SetOffAlarmNow() {
+ state = AlarmState::Alerting;
+ systemTask->PushMessage(System::Messages::SetOffAlarm);
+}
+
+void AlarmController::StopAlerting() {
+ systemTask->PushMessage(System::Messages::StopRinging);
+
+ // Alarm state is off unless this is a recurring alarm
+ if (recurrence == RecurType::None) {
+ state = AlarmState::Not_Set;
+ } else {
+ state = AlarmState::Set;
+ // set next instance
+ ScheduleAlarm();
+ }
+}
diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h
new file mode 100644
index 00000000..bf85d431
--- /dev/null
+++ b/src/components/alarm/AlarmController.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <cstdint>
+#include "app_timer.h"
+#include "components/datetime/DateTimeController.h"
+
+namespace Pinetime {
+ namespace System {
+ class SystemTask;
+ }
+ namespace Controllers {
+ class AlarmController {
+ public:
+ AlarmController(Controllers::DateTime& dateTimeController);
+
+ void Init(System::SystemTask* systemTask);
+ void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
+ void ScheduleAlarm();
+ void DisableAlarm();
+ void SetOffAlarmNow();
+ uint32_t SecondsToAlarm();
+ void StopAlerting();
+ enum class AlarmState { Not_Set, Set, Alerting };
+ enum class RecurType { None, Daily, Weekdays };
+ uint8_t Hours() const {
+ return hours;
+ }
+ uint8_t Minutes() const {
+ return minutes;
+ }
+ AlarmState State() const {
+ return state;
+ }
+ RecurType Recurrence() const {
+ return recurrence;
+ }
+ void SetRecurrence(RecurType recurType) {
+ recurrence = recurType;
+ }
+
+ private:
+ Controllers::DateTime& dateTimeController;
+ System::SystemTask* systemTask = nullptr;
+ uint8_t hours = 7;
+ uint8_t minutes = 0;
+ std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
+ AlarmState state = AlarmState::Not_Set;
+ RecurType recurrence = RecurType::None;
+ };
+ }
+}
diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp
index f8a64ecd..e807f033 100644
--- a/src/components/battery/BatteryController.cpp
+++ b/src/components/battery/BatteryController.cpp
@@ -1,4 +1,5 @@
#include "BatteryController.h"
+#include "drivers/PinMap.h"
#include <hal/nrf_gpio.h>
#include <nrfx_saadc.h>
#include <algorithm>
@@ -9,15 +10,22 @@ Battery* Battery::instance = nullptr;
Battery::Battery() {
instance = this;
+ nrf_gpio_cfg_input(PinMap::Charging, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Disabled);
}
-void Battery::Init() {
- nrf_gpio_cfg_input(chargingPin, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Pullup);
+void Battery::ReadPowerState() {
+ isCharging = !nrf_gpio_pin_read(PinMap::Charging);
+ isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent);
+
+ if (isPowerPresent && !isCharging) {
+ isFull = true;
+ } else if (!isPowerPresent) {
+ isFull = false;
+ }
}
-void Battery::Update() {
- isCharging = !nrf_gpio_pin_read(chargingPin);
- isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
+void Battery::MeasureVoltage() {
+ ReadPowerState();
if (isReading) {
return;
@@ -65,15 +73,26 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024;
- if (voltage > battery_max) {
- percentRemaining = 100;
+ uint8_t newPercent;
+ if (isFull) {
+ newPercent = 100;
} else if (voltage < battery_min) {
- percentRemaining = 0;
+ newPercent = 0;
} else {
- percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
+ newPercent = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100);
+ }
+
+ if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) {
+ firstMeasurement = false;
+ percentRemaining = newPercent;
+ systemTask->PushMessage(System::Messages::BatteryPercentageUpdated);
}
nrfx_saadc_uninit();
isReading = false;
}
}
+
+void Battery::Register(Pinetime::System::SystemTask* systemTask) {
+ this->systemTask = systemTask;
+}
diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h
index 6f09b737..5a7394c4 100644
--- a/src/components/battery/BatteryController.h
+++ b/src/components/battery/BatteryController.h
@@ -1,8 +1,7 @@
#pragma once
#include <cstdint>
#include <drivers/include/nrfx_saadc.h>
-#include <array>
-#include <numeric>
+#include <systemtask/SystemTask.h>
namespace Pinetime {
namespace Controllers {
@@ -11,8 +10,9 @@ namespace Pinetime {
public:
Battery();
- void Init();
- void Update();
+ void ReadPowerState();
+ void MeasureVoltage();
+ void Register(System::SystemTask* systemTask);
uint8_t PercentRemaining() const {
return percentRemaining;
@@ -23,7 +23,9 @@ namespace Pinetime {
}
bool IsCharging() const {
- return isCharging;
+ // isCharging will go up and down when fully charged
+ // isFull makes sure this returns false while fully charged.
+ return isCharging && !isFull;
}
bool IsPowerPresent() const {
@@ -34,14 +36,14 @@ namespace Pinetime {
static Battery* instance;
nrf_saadc_value_t saadc_value;
- static constexpr uint32_t chargingPin = 12;
- static constexpr uint32_t powerPresentPin = 19;
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
uint16_t voltage = 0;
uint8_t percentRemaining = 0;
+ bool isFull = false;
bool isCharging = false;
bool isPowerPresent = false;
+ bool firstMeasurement = true;
void SaadcInit();
@@ -49,6 +51,8 @@ namespace Pinetime {
static void AdcCallbackStatic(nrfx_saadc_evt_t const* event);
bool isReading = false;
+
+ Pinetime::System::SystemTask* systemTask = nullptr;
};
}
}
diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp
index c3d1d69a..5e5c25cf 100644
--- a/src/components/ble/AlertNotificationClient.cpp
+++ b/src/components/ble/AlertNotificationClient.cpp
@@ -55,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
return true;
}
- if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) {
+ if (service != nullptr && ble_uuid_cmp(&ansServiceUuid.u, &service->uuid.u) == 0) {
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
ansStartHandle = service->start_handle;
ansEndHandle = service->end_handle;
@@ -80,21 +80,21 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection
} else
onServiceDiscovered(connectionHandle);
} else {
- if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
+ if (characteristic != nullptr && ble_uuid_cmp(&supportedNewAlertCategoryUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
supportedNewAlertCategoryHandle = characteristic->val_handle;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&supportedUnreadAlertCategoryUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&newAlertUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
newAlertHandle = characteristic->val_handle;
newAlertDefHandle = characteristic->def_handle;
isCharacteristicDiscovered = true;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&unreadAlertStatusUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
unreadAlertStatusHandle = characteristic->val_handle;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&controlPointUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
controlPointHandle = characteristic->val_handle;
} else
@@ -119,7 +119,7 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
uint16_t characteristicValueHandle,
const ble_gatt_dsc* descriptor) {
if (error->status == 0) {
- if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) {
+ if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(&newAlertUuid.u, &descriptor->uuid.u)) {
if (newAlertDescriptorHandle == 0) {
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
newAlertDescriptorHandle = descriptor->handle;
diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp
index d5fc7f65..56fc595f 100644
--- a/src/components/ble/AlertNotificationService.cpp
+++ b/src/components/ble/AlertNotificationService.cpp
@@ -26,11 +26,8 @@ void AlertNotificationService::Init() {
}
AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager)
- : characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid,
- .access_cb = AlertNotificationCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE},
- {.uuid = (ble_uuid_t*) &notificationEventUuid,
+ : characteristicDefinition {{.uuid = &ansCharUuid.u, .access_cb = AlertNotificationCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE},
+ {.uuid = &notificationEventUuid.u,
.access_cb = AlertNotificationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY,
@@ -39,7 +36,7 @@ AlertNotificationService::AlertNotificationService(System::SystemTask& systemTas
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &ansUuid,
+ .uuid = &ansUuid.u,
.characteristics = characteristicDefinition},
{0},
},
@@ -123,4 +120,4 @@ void AlertNotificationService::MuteIncomingCall() {
}
ble_gattc_notify_custom(connectionHandle, eventHandle, om);
-} \ No newline at end of file
+}
diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp
index 7f176904..29178667 100644
--- a/src/components/ble/BatteryInformationService.cpp
+++ b/src/components/ble/BatteryInformationService.cpp
@@ -14,7 +14,7 @@ int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
: batteryController {batteryController},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
+ characteristicDefinition {{.uuid = &batteryLevelUuid.u,
.access_cb = BatteryInformationServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
@@ -23,7 +23,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
+ .uuid = &batteryInformationServiceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
@@ -43,7 +43,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand
ble_gatt_access_ctxt* context) {
if (attributeHandle == batteryLevelHandle) {
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
- static uint8_t batteryValue = batteryController.PercentRemaining();
+ uint8_t batteryValue = batteryController.PercentRemaining();
int res = os_mbuf_append(context->om, &batteryValue, 1);
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp
index c6e68312..90d1f0c7 100644
--- a/src/components/ble/CurrentTimeClient.cpp
+++ b/src/components/ble/CurrentTimeClient.cpp
@@ -47,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
return true;
}
- if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) {
+ if (service != nullptr && ble_uuid_cmp(&ctsServiceUuid.u, &service->uuid.u) == 0) {
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
isDiscovered = true;
ctsStartHandle = service->start_handle;
@@ -72,7 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
return 0;
}
- if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &currentTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
+ if (characteristic != nullptr && ble_uuid_cmp(&currentTimeCharacteristicUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
isCharacteristicDiscovered = true;
currentTimeHandle = characteristic->val_handle;
diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp
index b49be39c..eefb7ec1 100644
--- a/src/components/ble/CurrentTimeService.cpp
+++ b/src/components/ble/CurrentTimeService.cpp
@@ -53,7 +53,7 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
}
CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
- : characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid,
+ : characteristicDefinition {{.uuid = &ctChrUuid.u,
.access_cb = CTSCallback,
.arg = this,
@@ -62,7 +62,7 @@ CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &ctsUuid,
+ .uuid = &ctsUuid.u,
.characteristics = characteristicDefinition},
{0},
},
diff --git a/src/components/ble/DeviceInformationService.cpp b/src/components/ble/DeviceInformationService.cpp
index cf482079..778d6e35 100644
--- a/src/components/ble/DeviceInformationService.cpp
+++ b/src/components/ble/DeviceInformationService.cpp
@@ -56,37 +56,37 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
DeviceInformationService::DeviceInformationService()
: characteristicDefinition {{
- .uuid = (ble_uuid_t*) &manufacturerNameUuid,
+ .uuid = &manufacturerNameUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &modelNumberUuid,
+ .uuid = &modelNumberUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &serialNumberUuid,
+ .uuid = &serialNumberUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &fwRevisionUuid,
+ .uuid = &fwRevisionUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &hwRevisionUuid,
+ .uuid = &hwRevisionUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &swRevisionUuid,
+ .uuid = &swRevisionUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
@@ -95,7 +95,7 @@ DeviceInformationService::DeviceInformationService()
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &deviceInfoUuid,
+ .uuid = &deviceInfoUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
diff --git a/src/components/ble/DfuService.cpp b/src/components/ble/DfuService.cpp
index 4179994d..3d6416fa 100644
--- a/src/components/ble/DfuService.cpp
+++ b/src/components/ble/DfuService.cpp
@@ -33,21 +33,21 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
bleController {bleController},
dfuImage {spiNorFlash},
characteristicDefinition {{
- .uuid = (ble_uuid_t*) &packetCharacteristicUuid,
+ .uuid = &packetCharacteristicUuid.u,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
.val_handle = nullptr,
},
{
- .uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
+ .uuid = &controlPointCharacteristicUuid.u,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
.val_handle = nullptr,
},
{
- .uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
+ .uuid = &revisionCharacteristicUuid.u,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
@@ -60,7 +60,7 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &serviceUuid,
+ .uuid = &serviceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
@@ -81,9 +81,9 @@ int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandl
xTimerStart(timeoutTimer, 0);
}
- ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle);
- ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
- ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
+ ble_gatts_find_chr(&serviceUuid.u, &packetCharacteristicUuid.u, nullptr, &packetCharacteristicHandle);
+ ble_gatts_find_chr(&serviceUuid.u, &controlPointCharacteristicUuid.u, nullptr, &controlPointCharacteristicHandle);
+ ble_gatts_find_chr(&serviceUuid.u, &revisionCharacteristicUuid.u, nullptr, &revisionCharacteristicHandle);
if (attributeHandle == packetCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
@@ -164,10 +164,10 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
- (uint8_t) (bytesReceived & 0x000000FFu),
- (uint8_t) (bytesReceived >> 8u),
- (uint8_t) (bytesReceived >> 16u),
- (uint8_t) (bytesReceived >> 24u)};
+ (uint8_t)(bytesReceived & 0x000000FFu),
+ (uint8_t)(bytesReceived >> 8u),
+ (uint8_t)(bytesReceived >> 16u),
+ (uint8_t)(bytesReceived >> 24u)};
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
}
@@ -422,9 +422,9 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size,
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
for (uint32_t i = 0; i < size; i++) {
- crc = (uint8_t) (crc >> 8) | (crc << 8);
+ crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= p_data[i];
- crc ^= (uint8_t) (crc & 0xFF) >> 4;
+ crc ^= (uint8_t)(crc & 0xFF) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xFF) << 4) << 1;
}
diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp
index c556566b..5b00f492 100644
--- a/src/components/ble/HeartRateService.cpp
+++ b/src/components/ble/HeartRateService.cpp
@@ -18,7 +18,7 @@ namespace {
HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
: system {system},
heartRateController {heartRateController},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
+ characteristicDefinition {{.uuid = &heartRateMeasurementUuid.u,
.access_cb = HeartRateServiceServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
@@ -27,7 +27,7 @@ HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Control
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &heartRateServiceUuid,
+ .uuid = &heartRateServiceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp
index 820d3b6e..17ed1a96 100644
--- a/src/components/ble/ImmediateAlertService.cpp
+++ b/src/components/ble/ImmediateAlertService.cpp
@@ -32,7 +32,7 @@ ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& syste
Pinetime::Controllers::NotificationManager& notificationManager)
: systemTask {systemTask},
notificationManager {notificationManager},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid,
+ characteristicDefinition {{.uuid = &alertLevelUuid.u,
.access_cb = AlertLevelCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
@@ -41,7 +41,7 @@ ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& syste
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &immediateAlertServiceUuid,
+ .uuid = &immediateAlertServiceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
@@ -72,4 +72,4 @@ int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16
}
return 0;
-} \ No newline at end of file
+}
diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp
index e1c20bf1..b49148d2 100644
--- a/src/components/ble/NavigationService.cpp
+++ b/src/components/ble/NavigationService.cpp
@@ -20,54 +20,45 @@
#include "systemtask/SystemTask.h"
-int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
- auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
- return navService->OnCommand(conn_handle, attr_handle, ctxt);
-}
-
-Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
- navUuid.value[14] = navId[0];
- navUuid.value[15] = navId[1];
+namespace {
+ // 0001yyxx-78fc-48fe-8e23-433b3a1942d0
+ constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
+ return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
+ .value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x01, 0x00}};
+ }
- navFlagCharUuid.value[12] = navFlagCharId[0];
- navFlagCharUuid.value[13] = navFlagCharId[1];
- navFlagCharUuid.value[14] = navId[0];
- navFlagCharUuid.value[15] = navId[1];
+ // 00010000-78fc-48fe-8e23-433b3a1942d0
+ constexpr ble_uuid128_t BaseUuid() {
+ return CharUuid(0x00, 0x00);
+ }
- navNarrativeCharUuid.value[12] = navNarrativeCharId[0];
- navNarrativeCharUuid.value[13] = navNarrativeCharId[1];
- navNarrativeCharUuid.value[14] = navId[0];
- navNarrativeCharUuid.value[15] = navId[1];
+ constexpr ble_uuid128_t navUuid {BaseUuid()};
- navManDistCharUuid.value[12] = navManDistCharId[0];
- navManDistCharUuid.value[13] = navManDistCharId[1];
- navManDistCharUuid.value[14] = navId[0];
- navManDistCharUuid.value[15] = navId[1];
+ constexpr ble_uuid128_t navFlagCharUuid {CharUuid(0x01, 0x00)};
+ constexpr ble_uuid128_t navNarrativeCharUuid {CharUuid(0x02, 0x00)};
+ constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)};
+ constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)};
- navProgressCharUuid.value[12] = navProgressCharId[0];
- navProgressCharUuid.value[13] = navProgressCharId[1];
- navProgressCharUuid.value[14] = navId[0];
- navProgressCharUuid.value[15] = navId[1];
+ int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
+ auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
+ return navService->OnCommand(conn_handle, attr_handle, ctxt);
+ }
+} // namespace
+Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
characteristicDefinition[0] = {
- .uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
-
- characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid),
- .access_cb = NAVCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
- characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid),
- .access_cb = NAVCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
- characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid),
- .access_cb = NAVCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+ .uuid = &navFlagCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+
+ characteristicDefinition[1] = {
+ .uuid = &navNarrativeCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+ characteristicDefinition[2] = {
+ .uuid = &navManDistCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+ characteristicDefinition[3] = {
+ .uuid = &navProgressCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[4] = {0};
- serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition};
+ serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &navUuid.u, .characteristics = characteristicDefinition};
serviceDefinition[1] = {0};
m_progress = 0;
@@ -90,13 +81,13 @@ int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, ui
data[notifSize] = '\0';
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
char* s = (char*) &data[0];
- if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) {
+ if (ble_uuid_cmp(ctxt->chr->uuid, &navFlagCharUuid.u) == 0) {
m_flag = s;
- } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) {
+ } else if (ble_uuid_cmp(ctxt->chr->uuid, &navNarrativeCharUuid.u) == 0) {
m_narrative = s;
- } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) {
+ } else if (ble_uuid_cmp(ctxt->chr->uuid, &navManDistCharUuid.u) == 0) {
m_manDist = s;
- } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) {
+ } else if (ble_uuid_cmp(ctxt->chr->uuid, &navProgressCharUuid.u) == 0) {
m_progress = data[0];
}
}
diff --git a/src/components/ble/NavigationService.h b/src/components/ble/NavigationService.h
index 5aab263c..c0c77f35 100644
--- a/src/components/ble/NavigationService.h
+++ b/src/components/ble/NavigationService.h
@@ -26,10 +26,6 @@
#undef max
#undef min
-// c7e60000-78fc-48fe-8e23-433b3a1942d0
-#define NAVIGATION_SERVICE_UUID_BASE \
- { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
-
namespace Pinetime {
namespace System {
class SystemTask;
@@ -53,19 +49,6 @@ namespace Pinetime {
int getProgress();
private:
- static constexpr uint8_t navId[2] = {0x01, 0x00};
- static constexpr uint8_t navFlagCharId[2] = {0x01, 0x00};
- static constexpr uint8_t navNarrativeCharId[2] = {0x02, 0x00};
- static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
- static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
-
- ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
-
- ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
- ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
- ble_uuid128_t navManDistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
- ble_uuid128_t navProgressCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
-
struct ble_gatt_chr_def characteristicDefinition[5];
struct ble_gatt_svc_def serviceDefinition[2];
diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp
index 5eb227bf..879421e7 100644
--- a/src/components/ble/NimbleController.cpp
+++ b/src/components/ble/NimbleController.cpp
@@ -42,6 +42,19 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
}
+void nimble_on_reset(int reason) {
+ NRF_LOG_INFO("Resetting state; reason=%d\n", reason);
+}
+
+void nimble_on_sync(void) {
+ int rc;
+
+ rc = ble_hs_util_ensure_addr(0);
+ ASSERT(rc == 0);
+
+ nptr->StartAdvertising();
+}
+
int GAPEventCallback(struct ble_gap_event* event, void* arg) {
auto nimbleController = static_cast<NimbleController*>(arg);
return nimbleController->OnGAPEvent(event);
@@ -51,6 +64,10 @@ void NimbleController::Init() {
while (!ble_hs_synced()) {
}
+ nptr = this;
+ ble_hs_cfg.reset_cb = nimble_on_reset;
+ ble_hs_cfg.sync_cb = nimble_on_sync;
+
ble_svc_gap_init();
ble_svc_gatt_init();
@@ -64,28 +81,31 @@ void NimbleController::Init() {
batteryInformationService.Init();
immediateAlertService.Init();
heartRateService.Init();
- int res;
- res = ble_hs_util_ensure_addr(0);
- ASSERT(res == 0);
- res = ble_hs_id_infer_auto(0, &addrType);
- ASSERT(res == 0);
- res = ble_svc_gap_device_name_set(deviceName);
- ASSERT(res == 0);
+
+ int rc;
+ rc = ble_hs_util_ensure_addr(0);
+ ASSERT(rc == 0);
+ rc = ble_hs_id_infer_auto(0, &addrType);
+ ASSERT(rc == 0);
+ rc = ble_svc_gap_device_name_set(deviceName);
+ ASSERT(rc == 0);
+ rc = ble_svc_gap_device_appearance_set(0xC2);
+ ASSERT(rc == 0);
Pinetime::Controllers::Ble::BleAddress address;
- res = ble_hs_id_copy_addr(addrType, address.data(), nullptr);
- ASSERT(res == 0);
+ rc = ble_hs_id_copy_addr(addrType, address.data(), nullptr);
+ ASSERT(rc == 0);
bleController.AddressType((addrType == 0) ? Ble::AddressTypes::Public : Ble::AddressTypes::Random);
bleController.Address(std::move(address));
- res = ble_gatts_start();
- ASSERT(res == 0);
+ rc = ble_gatts_start();
+ ASSERT(rc == 0);
+
+ if (!ble_gap_adv_active() && !bleController.IsConnected())
+ StartAdvertising();
}
void NimbleController::StartAdvertising() {
- if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active())
- return;
-
- ble_svc_gap_device_name_set(deviceName);
+ int rc;
/* set adv parameters */
struct ble_gap_adv_params adv_params;
@@ -102,11 +122,17 @@ void NimbleController::StartAdvertising() {
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+ /* fast advertise for 30 sec */
+ if (fastAdvCount < 15) {
+ adv_params.itvl_min = 32;
+ adv_params.itvl_max = 47;
+ fastAdvCount++;
+ } else {
+ adv_params.itvl_min = 1636;
+ adv_params.itvl_max = 1651;
+ }
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
- // fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
- // 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- // 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
fields.uuids128 = &dfuServiceUuid;
fields.num_uuids128 = 1;
fields.uuids128_is_complete = 1;
@@ -116,28 +142,25 @@ void NimbleController::StartAdvertising() {
rsp_fields.name_len = strlen(deviceName);
rsp_fields.name_is_complete = 1;
- ble_gap_adv_set_fields(&fields);
- // ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
+ rc = ble_gap_adv_set_fields(&fields);
+ ASSERT(rc == 0);
- ble_gap_adv_rsp_set_fields(&rsp_fields);
- // ASSERT(res == 0);
+ rc = ble_gap_adv_rsp_set_fields(&rsp_fields);
+ ASSERT(rc == 0);
- ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
- // ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
- // For now, the advertising is restarted as soon as it ends. There may be a race condition
- // that prevent the advertising from restarting reliably.
- // I remove the assert to prevent this uncesseray crash, but in the long term, the management of
- // the advertising should be improve (better error handling, and advertise for 3 minutes after
- // the application has been woken up, for example.
+ rc = ble_gap_adv_start(addrType, NULL, 2000, &adv_params, GAPEventCallback, this);
+ ASSERT(rc == 0);
}
int NimbleController::OnGAPEvent(ble_gap_event* event) {
switch (event->type) {
case BLE_GAP_EVENT_ADV_COMPLETE:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
- NRF_LOG_INFO("advertise complete; reason=%dn status=%d", event->adv_complete.reason, event->connect.status);
+ NRF_LOG_INFO("reason=%d; status=%d", event->adv_complete.reason, event->connect.status);
+ StartAdvertising();
break;
- case BLE_GAP_EVENT_CONNECT: {
+
+ case BLE_GAP_EVENT_CONNECT:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
/* A new connection was established or a connection attempt failed. */
@@ -145,35 +168,44 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
if (event->connect.status != 0) {
/* Connection failed; resume advertising. */
- StartAdvertising();
+ currentTimeClient.Reset();
+ alertNotificationClient.Reset();
+ connectionHandle = BLE_HS_CONN_HANDLE_NONE;
bleController.Disconnect();
+ fastAdvCount = 0;
+ StartAdvertising();
} else {
+ connectionHandle = event->connect.conn_handle;
bleController.Connect();
systemTask.PushMessage(Pinetime::System::Messages::BleConnected);
- connectionHandle = event->connect.conn_handle;
- // Service discovery is deffered via systemtask
+ // Service discovery is deferred via systemtask
}
- } break;
+ break;
+
case BLE_GAP_EVENT_DISCONNECT:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
- NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
+ NRF_LOG_INFO("disconnect reason=%d", event->disconnect.reason);
/* Connection terminated; resume advertising. */
currentTimeClient.Reset();
alertNotificationClient.Reset();
connectionHandle = BLE_HS_CONN_HANDLE_NONE;
bleController.Disconnect();
+ fastAdvCount = 0;
StartAdvertising();
break;
+
case BLE_GAP_EVENT_CONN_UPDATE:
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONN_UPDATE");
/* The central has updated the connection parameters. */
- NRF_LOG_INFO("connection updated; status=%d ", event->conn_update.status);
+ NRF_LOG_INFO("update status=%d ", event->conn_update.status);
break;
+
case BLE_GAP_EVENT_ENC_CHANGE:
/* Encryption has been enabled or disabled for this connection. */
NRF_LOG_INFO("encryption change event; status=%d ", event->enc_change.status);
- return 0;
+ break;
+
case BLE_GAP_EVENT_SUBSCRIBE:
NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d "
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
@@ -183,10 +215,12 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
event->subscribe.prev_notify,
event->subscribe.cur_notify,
event->subscribe.prev_indicate);
- return 0;
+ break;
+
case BLE_GAP_EVENT_MTU:
- NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
- return 0;
+ NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
+ event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
+ break;
case BLE_GAP_EVENT_REPEAT_PAIRING: {
/* We already have a bond with the peer, but it is attempting to
@@ -217,8 +251,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
notifSize);
alertNotificationClient.OnNotification(event);
- return 0;
- }
+ } break;
/* Attribute data is contained in event->notify_rx.attr_data. */
default:
@@ -229,7 +262,9 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
}
void NimbleController::StartDiscovery() {
- serviceDiscovery.StartDiscovery(connectionHandle);
+ if (connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
+ serviceDiscovery.StartDiscovery(connectionHandle);
+ }
}
uint16_t NimbleController::connHandle() {
@@ -237,7 +272,7 @@ uint16_t NimbleController::connHandle() {
}
void NimbleController::NotifyBatteryLevel(uint8_t level) {
- if(connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
+ if (connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
batteryInformationService.NotifyBatteryLevel(connectionHandle, level);
}
}
diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h
index 0cfe983c..473bb1af 100644
--- a/src/components/ble/NimbleController.h
+++ b/src/components/ble/NimbleController.h
@@ -72,6 +72,10 @@ namespace Pinetime {
uint16_t connHandle();
void NotifyBatteryLevel(uint8_t level);
+ void RestartFastAdv() {
+ fastAdvCount = 0;
+ }
+
private:
static constexpr const char* deviceName = "InfiniTime";
Pinetime::System::SystemTask& systemTask;
@@ -94,6 +98,7 @@ namespace Pinetime {
uint8_t addrType; // 1 = Random, 0 = PUBLIC
uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;
+ uint8_t fastAdvCount = 0;
ble_uuid128_t dfuServiceUuid {
.u {.type = BLE_UUID_TYPE_128},
@@ -101,5 +106,7 @@ namespace Pinetime {
ServiceDiscovery serviceDiscovery;
};
+
+ static NimbleController* nptr;
}
}
diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp
index b1b0e6b2..7ffed300 100644
--- a/src/components/ble/NotificationManager.cpp
+++ b/src/components/ble/NotificationManager.cpp
@@ -79,14 +79,6 @@ bool NotificationManager::AreNewNotificationsAvailable() {
return newNotification;
}
-bool NotificationManager::IsVibrationEnabled() {
- return vibrationEnabled;
-}
-
-void NotificationManager::ToggleVibrations() {
- vibrationEnabled = !vibrationEnabled;
-}
-
bool NotificationManager::ClearNewNotificationFlag() {
return newNotification.exchange(false);
}
diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h
index d4072cc2..40f174ea 100644
--- a/src/components/ble/NotificationManager.h
+++ b/src/components/ble/NotificationManager.h
@@ -44,8 +44,6 @@ namespace Pinetime {
Notification GetPrevious(Notification::Id id);
bool ClearNewNotificationFlag();
bool AreNewNotificationsAvailable();
- bool IsVibrationEnabled();
- void ToggleVibrations();
static constexpr size_t MaximumMessageSize() {
return MessageSize;
@@ -60,7 +58,6 @@ namespace Pinetime {
uint8_t writeIndex = 0;
bool empty = true;
std::atomic<bool> newNotification {false};
- bool vibrationEnabled = true;
};
}
-} \ No newline at end of file
+}
diff --git a/src/components/brightness/BrightnessController.cpp b/src/components/brightness/BrightnessController.cpp
index 8ad987d1..6c524679 100644
--- a/src/components/brightness/BrightnessController.cpp
+++ b/src/components/brightness/BrightnessController.cpp
@@ -1,13 +1,13 @@
#include "BrightnessController.h"
#include <hal/nrf_gpio.h>
#include "displayapp/screens/Symbols.h"
-
+#include "drivers/PinMap.h"
using namespace Pinetime::Controllers;
void BrightnessController::Init() {
- nrf_gpio_cfg_output(pinLcdBacklight1);
- nrf_gpio_cfg_output(pinLcdBacklight2);
- nrf_gpio_cfg_output(pinLcdBacklight3);
+ nrf_gpio_cfg_output(PinMap::LcdBacklightLow);
+ nrf_gpio_cfg_output(PinMap::LcdBacklightMedium);
+ nrf_gpio_cfg_output(PinMap::LcdBacklightHigh);
Set(level);
}
@@ -16,24 +16,24 @@ void BrightnessController::Set(BrightnessController::Levels level) {
switch (level) {
default:
case Levels::High:
- nrf_gpio_pin_clear(pinLcdBacklight1);
- nrf_gpio_pin_clear(pinLcdBacklight2);
- nrf_gpio_pin_clear(pinLcdBacklight3);
+ nrf_gpio_pin_clear(PinMap::LcdBacklightLow);
+ nrf_gpio_pin_clear(PinMap::LcdBacklightMedium);
+ nrf_gpio_pin_clear(PinMap::LcdBacklightHigh);
break;
case Levels::Medium:
- nrf_gpio_pin_clear(pinLcdBacklight1);
- nrf_gpio_pin_clear(pinLcdBacklight2);
- nrf_gpio_pin_set(pinLcdBacklight3);
+ nrf_gpio_pin_clear(PinMap::LcdBacklightLow);
+ nrf_gpio_pin_clear(PinMap::LcdBacklightMedium);
+ nrf_gpio_pin_set(PinMap::LcdBacklightHigh);
break;
case Levels::Low:
- nrf_gpio_pin_clear(pinLcdBacklight1);
- nrf_gpio_pin_set(pinLcdBacklight2);
- nrf_gpio_pin_set(pinLcdBacklight3);
+ nrf_gpio_pin_clear(PinMap::LcdBacklightLow);
+ nrf_gpio_pin_set(PinMap::LcdBacklightMedium);
+ nrf_gpio_pin_set(PinMap::LcdBacklightHigh);
break;
case Levels::Off:
- nrf_gpio_pin_set(pinLcdBacklight1);
- nrf_gpio_pin_set(pinLcdBacklight2);
- nrf_gpio_pin_set(pinLcdBacklight3);
+ nrf_gpio_pin_set(PinMap::LcdBacklightLow);
+ nrf_gpio_pin_set(PinMap::LcdBacklightMedium);
+ nrf_gpio_pin_set(PinMap::LcdBacklightHigh);
break;
}
}
diff --git a/src/components/brightness/BrightnessController.h b/src/components/brightness/BrightnessController.h
index c47158a9..0d7ac2ff 100644
--- a/src/components/brightness/BrightnessController.h
+++ b/src/components/brightness/BrightnessController.h
@@ -22,9 +22,6 @@ namespace Pinetime {
const char* ToString();
private:
- static constexpr uint8_t pinLcdBacklight1 = 14;
- static constexpr uint8_t pinLcdBacklight2 = 22;
- static constexpr uint8_t pinLcdBacklight3 = 23;
Levels level = Levels::High;
Levels backupLevel = Levels::High;
};
diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp
index d6aa83c8..e9c5d870 100644
--- a/src/components/datetime/DateTimeController.cpp
+++ b/src/components/datetime/DateTimeController.cpp
@@ -5,6 +5,17 @@
using namespace Pinetime::Controllers;
+namespace {
+ char const* DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
+ char const* MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
+ char const* MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+}
+
+void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
+ this->currentDateTime = t;
+ UpdateTime(previousSystickCounter); // Update internal state without updating the time
+}
+
void DateTime::SetTime(
uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
std::tm tm = {
@@ -67,7 +78,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
// Notify new day to SystemTask
if (hour == 0 and not isMidnightAlreadyNotified) {
isMidnightAlreadyNotified = true;
- if(systemTask != nullptr)
+ if (systemTask != nullptr)
systemTask->PushMessage(System::Messages::OnNewDay);
} else if (hour != 0) {
isMidnightAlreadyNotified = false;
@@ -75,48 +86,18 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
}
const char* DateTime::MonthShortToString() {
- return DateTime::MonthsString[static_cast<uint8_t>(month)];
-}
-
-const char* DateTime::MonthShortToStringLow() {
- return DateTime::MonthsStringLow[static_cast<uint8_t>(month)];
-}
-
-const char* DateTime::MonthsToStringLow() {
- return DateTime::MonthsLow[static_cast<uint8_t>(month)];
-}
-
-const char* DateTime::DayOfWeekToString() {
- return DateTime::DaysString[static_cast<uint8_t>(dayOfWeek)];
+ return MonthsString[static_cast<uint8_t>(month)];
}
const char* DateTime::DayOfWeekShortToString() {
- return DateTime::DaysStringShort[static_cast<uint8_t>(dayOfWeek)];
-}
-
-const char* DateTime::DayOfWeekToStringLow() {
- return DateTime::DaysStringLow[static_cast<uint8_t>(dayOfWeek)];
+ return DaysStringShort[static_cast<uint8_t>(dayOfWeek)];
}
-const char* DateTime::DayOfWeekShortToStringLow() {
- return DateTime::DaysStringShortLow[static_cast<uint8_t>(dayOfWeek)];
+const char* DateTime::MonthShortToStringLow(Months month) {
+ return MonthsStringLow[static_cast<uint8_t>(month)];
}
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
this->systemTask = systemTask;
}
-char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
-
-char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
-
-char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
-
-char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"};
-
-char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
-
-char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
-char const* DateTime::MonthsLow[] = {
- "--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; \ No newline at end of file
diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h
index 265d6e9d..77ed68e8 100644
--- a/src/components/datetime/DateTimeController.h
+++ b/src/components/datetime/DateTimeController.h
@@ -59,12 +59,8 @@ namespace Pinetime {
}
const char* MonthShortToString();
- const char* MonthShortToStringLow();
- const char* MonthsToStringLow();
- const char* DayOfWeekToString();
const char* DayOfWeekShortToString();
- const char* DayOfWeekToStringLow();
- const char* DayOfWeekShortToStringLow();
+ static const char* MonthShortToStringLow(Months month);
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
return currentDateTime;
@@ -74,6 +70,7 @@ namespace Pinetime {
}
void Register(System::SystemTask* systemTask);
+ void SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t);
private:
uint16_t year = 0;
@@ -90,14 +87,6 @@ namespace Pinetime {
bool isMidnightAlreadyNotified = false;
System::SystemTask* systemTask = nullptr;
-
- static char const* DaysString[];
- static char const* DaysStringShort[];
- static char const* DaysStringLow[];
- static char const* DaysStringShortLow[];
- static char const* MonthsString[];
- static char const* MonthsStringLow[];
- static char const* MonthsLow[];
};
}
-} \ No newline at end of file
+}
diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h
index 1f2eb7e0..75ba16c8 100644
--- a/src/components/fs/FS.h
+++ b/src/components/fs/FS.h
@@ -53,7 +53,7 @@ namespace Pinetime {
*
*/
static constexpr size_t startAddress = 0x0B4000;
- static constexpr size_t size = 0x3C0000;
+ static constexpr size_t size = 0x34C000;
static constexpr size_t blockSize = 4096;
bool resourcesValid = false;
diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp
index b25e6bc8..f596c718 100644
--- a/src/components/motor/MotorController.cpp
+++ b/src/components/motor/MotorController.cpp
@@ -2,18 +2,16 @@
#include <hal/nrf_gpio.h>
#include "systemtask/SystemTask.h"
#include "app_timer.h"
+#include "drivers/PinMap.h"
APP_TIMER_DEF(shortVibTimer);
APP_TIMER_DEF(longVibTimer);
using namespace Pinetime::Controllers;
-MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
-}
-
void MotorController::Init() {
- nrf_gpio_cfg_output(pinMotor);
- nrf_gpio_pin_set(pinMotor);
+ nrf_gpio_cfg_output(PinMap::Motor);
+ nrf_gpio_pin_set(PinMap::Motor);
app_timer_init();
app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, StopMotor);
@@ -26,27 +24,20 @@ void MotorController::Ring(void* p_context) {
}
void MotorController::RunForDuration(uint8_t motorDuration) {
- if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
- return;
- }
-
- nrf_gpio_pin_clear(pinMotor);
+ nrf_gpio_pin_clear(PinMap::Motor);
app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr);
}
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);
+ nrf_gpio_pin_set(PinMap::Motor);
}
void MotorController::StopMotor(void* p_context) {
- nrf_gpio_pin_set(pinMotor);
+ nrf_gpio_pin_set(PinMap::Motor);
}
diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h
index d2c9fe5f..c9326d57 100644
--- a/src/components/motor/MotorController.h
+++ b/src/components/motor/MotorController.h
@@ -1,16 +1,14 @@
#pragma once
#include <cstdint>
-#include "app_timer.h"
-#include "components/settings/Settings.h"
namespace Pinetime {
namespace Controllers {
- static constexpr uint8_t pinMotor = 16;
class MotorController {
public:
- MotorController(Controllers::Settings& settingsController);
+ MotorController() = default;
+
void Init();
void RunForDuration(uint8_t motorDuration);
void StartRinging();
@@ -18,7 +16,6 @@ namespace Pinetime {
private:
static void Ring(void* p_context);
- Controllers::Settings& settingsController;
static void StopMotor(void* p_context);
};
}
diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h
index 93d6d217..871ff3b6 100644
--- a/src/components/settings/Settings.h
+++ b/src/components/settings/Settings.h
@@ -11,12 +11,20 @@ namespace Pinetime {
class Settings {
public:
enum class ClockType : uint8_t { H24, H12 };
- enum class Vibration : uint8_t { ON, OFF };
+ enum class Notification : uint8_t { ON, OFF };
enum class WakeUpMode : uint8_t {
SingleTap = 0,
DoubleTap = 1,
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);
@@ -33,10 +41,38 @@ namespace Pinetime {
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) {
appMenu = menu;
};
- uint8_t GetAppMenu() {
+
+ uint8_t GetAppMenu() const {
return appMenu;
};
@@ -57,14 +93,14 @@ namespace Pinetime {
return settings.clockType;
};
- void SetVibrationStatus(Vibration status) {
- if (status != settings.vibrationStatus) {
+ void SetNotificationStatus(Notification status) {
+ if (status != settings.notificationStatus) {
settingsChanged = true;
}
- settings.vibrationStatus = status;
+ settings.notificationStatus = status;
};
- Vibration GetVibrationStatus() const {
- return settings.vibrationStatus;
+ Notification GetNotificationStatus() const {
+ return settings.notificationStatus;
};
void SetScreenTimeOut(uint32_t timeout) {
@@ -78,7 +114,7 @@ namespace Pinetime {
};
void setWakeUpMode(WakeUpMode wakeUp, bool enabled) {
- if (!isWakeUpModeOn(wakeUp)) {
+ if (enabled != isWakeUpModeOn(wakeUp)) {
settingsChanged = true;
}
settings.wakeUpMode.set(static_cast<size_t>(wakeUp), enabled);
@@ -127,18 +163,19 @@ namespace Pinetime {
private:
Pinetime::Controllers::FS& fs;
- static constexpr uint32_t settingsVersion = 0x0001;
+ static constexpr uint32_t settingsVersion = 0x0002;
struct SettingsData {
-
uint32_t version = settingsVersion;
uint32_t stepsGoal = 10000;
uint32_t screenTimeOut = 15000;
ClockType clockType = ClockType::H24;
- Vibration vibrationStatus = Vibration::ON;
+ Notification notificationStatus = Notification::ON;
uint8_t clockFace = 0;
+ PineTimeStyle PTS;
+
std::bitset<3> wakeUpMode {0};
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h
index 684e3a46..d340efee 100644
--- a/src/displayapp/Apps.h
+++ b/src/displayapp/Apps.h
@@ -12,6 +12,7 @@ namespace Pinetime {
NotificationsPreview,
Notifications,
Timer,
+ Alarm,
FlashLight,
BatteryInfo,
Music,
@@ -30,7 +31,11 @@ namespace Pinetime {
SettingTimeFormat,
SettingDisplay,
SettingWakeUp,
- SettingSteps
+ SettingSteps,
+ SettingPineTimeStyle,
+ SettingSetDate,
+ SettingSetTime,
+ Error,
};
}
}
diff --git a/src/displayapp/Colors.cpp b/src/displayapp/Colors.cpp
new file mode 100644
index 00000000..f45f0722
--- /dev/null
+++ b/src/displayapp/Colors.cpp
@@ -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;
+ }
+}
diff --git a/src/displayapp/Colors.h b/src/displayapp/Colors.h
new file mode 100644
index 00000000..9db7dd20
--- /dev/null
+++ b/src/displayapp/Colors.h
@@ -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);
+ }
+} \ No newline at end of file
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index 8cb8ed15..6e5cb576 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -3,6 +3,7 @@
#include <displayapp/screens/HeartRate.h>
#include <displayapp/screens/Motion.h>
#include <displayapp/screens/Timer.h>
+#include <displayapp/screens/Alarm.h>
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/datetime/DateTimeController.h"
@@ -28,6 +29,7 @@
#include "displayapp/screens/FlashLight.h"
#include "displayapp/screens/BatteryInfo.h"
#include "displayapp/screens/Steps.h"
+#include "displayapp/screens/Error.h"
#include "drivers/Cst816s.h"
#include "drivers/St7789.h"
@@ -42,6 +44,9 @@
#include "displayapp/screens/settings/SettingWakeUp.h"
#include "displayapp/screens/settings/SettingDisplay.h"
#include "displayapp/screens/settings/SettingSteps.h"
+#include "displayapp/screens/settings/SettingPineTimeStyle.h"
+#include "displayapp/screens/settings/SettingSetDate.h"
+#include "displayapp/screens/settings/SettingSetTime.h"
#include "libs/lv_conf.h"
@@ -89,6 +94,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler)
: lcd {lcd},
lvgl {lvgl},
@@ -103,14 +109,20 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
motorController {motorController},
motionController {motionController},
timerController {timerController},
+ alarmController {alarmController},
touchHandler {touchHandler} {
}
-void DisplayApp::Start() {
+void DisplayApp::Start(System::BootErrors error) {
msgQueue = xQueueCreate(queueSize, itemSize);
- // Start clock when smartwatch boots
- LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
+ bootError = error;
+
+ if (error == System::BootErrors::TouchController) {
+ LoadApp(Apps::Error, DisplayApp::FullRefreshDirections::None);
+ } else {
+ LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
+ }
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) {
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
@@ -135,24 +147,17 @@ void DisplayApp::InitHw() {
brightnessController.Set(settingsController.GetBrightness());
}
-uint32_t acc = 0;
-uint32_t count = 0;
-bool toggle = true;
void DisplayApp::Refresh() {
TickType_t queueTimeout;
- TickType_t delta;
switch (state) {
case States::Idle:
- IdleState();
queueTimeout = portMAX_DELAY;
break;
case States::Running:
- RunningState();
- delta = xTaskGetTickCount() - lastWakeTime;
- if (delta > LV_DISP_DEF_REFR_PERIOD) {
- delta = LV_DISP_DEF_REFR_PERIOD;
+ if (!currentScreen->IsRunning()) {
+ LoadApp(returnToApp, returnDirection);
}
- queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta;
+ queueTimeout = lv_task_handler();
break;
default:
queueTimeout = portMAX_DELAY;
@@ -160,9 +165,7 @@ void DisplayApp::Refresh() {
}
Messages msg;
- bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout);
- lastWakeTime = xTaskGetTickCount();
- if (messageReceived) {
+ if (xQueueReceive(msgQueue, &msg, queueTimeout)) {
switch (msg) {
case Messages::DimScreen:
// Backup brightness is the brightness to return to after dimming or sleeping
@@ -193,9 +196,6 @@ void DisplayApp::Refresh() {
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
// Screens::Clock::BleConnectionStates::NotConnected);
break;
- case Messages::UpdateBatteryLevel:
- batteryController.Update();
- break;
case Messages::NewNotification:
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
break;
@@ -207,6 +207,13 @@ void DisplayApp::Refresh() {
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
}
break;
+ case Messages::AlarmTriggered:
+ if (currentApp == Apps::Alarm) {
+ auto* alarm = static_cast<Screens::Alarm*>(currentScreen.get());
+ alarm->SetAlerting();
+ } else {
+ LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None);
+ }
case Messages::TouchEvent: {
if (state != States::Running) {
break;
@@ -274,13 +281,6 @@ void DisplayApp::Refresh() {
}
}
-void DisplayApp::RunningState() {
- if (!currentScreen->Refresh()) {
- LoadApp(returnToApp, returnDirection);
- }
- lv_task_handler();
-}
-
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
nextApp = app;
nextDirection = direction;
@@ -317,6 +317,11 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
motionController);
break;
+ case Apps::Error:
+ currentScreen = std::make_unique<Screens::Error>(this, bootError);
+ ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
+ break;
+
case Apps::FirmwareValidation:
currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
@@ -339,6 +344,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
case Apps::Timer:
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
break;
+ case Apps::Alarm:
+ currentScreen = std::make_unique<Screens::Alarm>(this, alarmController);
+ break;
// Settings
case Apps::QuickSettings:
@@ -370,13 +378,25 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
+ case Apps::SettingSetDate:
+ currentScreen = std::make_unique<Screens::SettingSetDate>(this, dateTimeController);
+ ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
+ case Apps::SettingSetTime:
+ currentScreen = std::make_unique<Screens::SettingSetTime>(this, dateTimeController);
+ ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
+ case Apps::SettingPineTimeStyle:
+ currentScreen = std::make_unique<Screens::SettingPineTimeStyle>(this, settingsController);
+ ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
case Apps::BatteryInfo:
currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::SysInfo:
currentScreen = std::make_unique<Screens::SystemInfo>(
- this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController);
+ this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController, touchPanel);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::FlashLight:
@@ -418,9 +438,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentApp = app;
}
-void DisplayApp::IdleState() {
-}
-
void DisplayApp::PushMessage(Messages msg) {
if (in_isr()) {
BaseType_t xHigherPriorityTaskWoken;
diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h
index 96951d1c..a87cab0b 100644
--- a/src/displayapp/DisplayApp.h
+++ b/src/displayapp/DisplayApp.h
@@ -14,8 +14,11 @@
#include "components/settings/Settings.h"
#include "displayapp/screens/Screen.h"
#include "components/timer/TimerController.h"
+#include "components/alarm/AlarmController.h"
#include "touchhandler/TouchHandler.h"
+
#include "Messages.h"
+#include "BootErrors.h"
namespace Pinetime {
@@ -57,8 +60,9 @@ namespace Pinetime {
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler);
- void Start();
+ void Start(System::BootErrors error);
void PushMessage(Display::Messages msg);
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
@@ -82,6 +86,7 @@ namespace Pinetime {
Pinetime::Controllers::MotorController& motorController;
Pinetime::Controllers::MotionController& motionController;
Pinetime::Controllers::TimerController& timerController;
+ Pinetime::Controllers::AlarmController& alarmController;
Pinetime::Controllers::TouchHandler& touchHandler;
Pinetime::Controllers::FirmwareValidator validator;
@@ -103,8 +108,6 @@ namespace Pinetime {
TouchEvents returnTouchEvent = TouchEvents::None;
TouchEvents GetGesture();
- void RunningState();
- void IdleState();
static void Process(void* instance);
void InitHw();
void Refresh();
@@ -114,7 +117,7 @@ namespace Pinetime {
Apps nextApp = Apps::None;
DisplayApp::FullRefreshDirections nextDirection;
- TickType_t lastWakeTime;
+ System::BootErrors bootError;
};
}
}
diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp
index 17612ef0..a42d81a2 100644
--- a/src/displayapp/DisplayAppRecovery.cpp
+++ b/src/displayapp/DisplayAppRecovery.cpp
@@ -5,6 +5,7 @@
#include <components/rle/RleDecoder.h>
#include <touchhandler/TouchHandler.h>
#include "displayapp/icons/infinitime/infinitime-nb.c"
+#include "components/ble/BleController.h"
using namespace Pinetime::Applications;
@@ -21,6 +22,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler)
: lcd {lcd}, bleController {bleController} {
diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h
index 8b2bc7f5..425e0aca 100644
--- a/src/displayapp/DisplayAppRecovery.h
+++ b/src/displayapp/DisplayAppRecovery.h
@@ -6,32 +6,39 @@
#include <bits/unique_ptr.h>
#include <queue.h>
#include "components/gfx/Gfx.h"
-#include "components/battery/BatteryController.h"
-#include "components/brightness/BrightnessController.h"
-#include "components/ble/BleController.h"
-#include "components/datetime/DateTimeController.h"
-#include "components/ble/NotificationManager.h"
-#include "components/firmwarevalidator/FirmwareValidator.h"
#include "drivers/Cst816s.h"
#include <date/date.h>
#include <drivers/Watchdog.h>
-#include <components/heartrate/HeartRateController.h>
-#include <components/motion/MotionController.h>
#include <components/motor/MotorController.h>
-#include <components/settings/Settings.h>
#include "TouchEvents.h"
#include "Apps.h"
#include "Messages.h"
#include "DummyLittleVgl.h"
-#include "components/timer/TimerController.h"
namespace Pinetime {
- namespace System {
- class SystemTask;
- };
+ namespace Drivers {
+ class St7789;
+ class Cst816S;
+ class WatchdogView;
+ }
namespace Controllers {
+ class Settings;
+ class Battery;
+ class Ble;
+ class DateTime;
+ class NotificationManager;
+ class HeartRateController;
+ class MotionController;
class TouchHandler;
+ class MotorController;
+ class TimerController;
+ class AlarmController;
}
+
+ namespace System {
+ class SystemTask;
+ };
+
namespace Applications {
class DisplayApp {
public:
@@ -48,6 +55,7 @@ namespace Pinetime {
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler);
void Start();
void PushMessage(Pinetime::Applications::Display::Messages msg);
diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h
index 322505e6..d48b646f 100644
--- a/src/displayapp/Messages.h
+++ b/src/displayapp/Messages.h
@@ -7,7 +7,6 @@ namespace Pinetime {
GoToRunning,
UpdateDateTime,
UpdateBleConnection,
- UpdateBatteryLevel,
TouchEvent,
ButtonPushed,
NewNotification,
@@ -15,7 +14,8 @@ namespace Pinetime {
BleFirmwareUpdateStarted,
UpdateTimeOut,
DimScreen,
- RestoreBrightness
+ RestoreBrightness,
+ AlarmTriggered
};
}
}
diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp
new file mode 100644
index 00000000..6b45a36e
--- /dev/null
+++ b/src/displayapp/screens/Alarm.cpp
@@ -0,0 +1,265 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "Alarm.h"
+#include "Screen.h"
+#include "Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+using Pinetime::Controllers::AlarmController;
+
+static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
+ Alarm* screen = static_cast<Alarm*>(obj->user_data);
+ screen->OnButtonEvent(obj, event);
+}
+
+Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController)
+ : Screen(app), running {true}, alarmController {alarmController} {
+
+ time = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
+ lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+
+ alarmHours = alarmController.Hours();
+ alarmMinutes = alarmController.Minutes();
+ lv_label_set_text_fmt(time, "%02lu:%02lu", alarmHours, alarmMinutes);
+
+ lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25);
+
+ btnHoursUp = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursUp->user_data = this;
+ lv_obj_set_event_cb(btnHoursUp, btnEventHandler);
+ lv_obj_set_size(btnHoursUp, 60, 40);
+ lv_obj_align(btnHoursUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -85);
+ txtHrUp = lv_label_create(btnHoursUp, nullptr);
+ lv_label_set_text_static(txtHrUp, "+");
+
+ btnHoursDown = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursDown->user_data = this;
+ lv_obj_set_event_cb(btnHoursDown, btnEventHandler);
+ lv_obj_set_size(btnHoursDown, 60, 40);
+ lv_obj_align(btnHoursDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, 35);
+ txtHrDown = lv_label_create(btnHoursDown, nullptr);
+ lv_label_set_text_static(txtHrDown, "-");
+
+ btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesUp->user_data = this;
+ lv_obj_set_event_cb(btnMinutesUp, btnEventHandler);
+ lv_obj_set_size(btnMinutesUp, 60, 40);
+ lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, -85);
+ txtMinUp = lv_label_create(btnMinutesUp, nullptr);
+ lv_label_set_text_static(txtMinUp, "+");
+
+ btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesDown->user_data = this;
+ lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
+ lv_obj_set_size(btnMinutesDown, 60, 40);
+ lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, 35);
+ txtMinDown = lv_label_create(btnMinutesDown, nullptr);
+ lv_label_set_text_static(txtMinDown, "-");
+
+ btnEnable = lv_btn_create(lv_scr_act(), nullptr);
+ btnEnable->user_data = this;
+ lv_obj_set_event_cb(btnEnable, btnEventHandler);
+ lv_obj_set_size(btnEnable, 115, 50);
+ lv_obj_align(btnEnable, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
+ txtEnable = lv_label_create(btnEnable, nullptr);
+ SetEnableButtonState();
+
+ btnRecur = lv_btn_create(lv_scr_act(), nullptr);
+ btnRecur->user_data = this;
+ lv_obj_set_event_cb(btnRecur, btnEventHandler);
+ lv_obj_set_size(btnRecur, 115, 50);
+ lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
+ txtRecur = lv_label_create(btnRecur, nullptr);
+ SetRecurButtonState();
+
+ btnInfo = lv_btn_create(lv_scr_act(), nullptr);
+ btnInfo->user_data = this;
+ lv_obj_set_event_cb(btnInfo, btnEventHandler);
+ lv_obj_set_size(btnInfo, 50, 40);
+ lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85);
+ txtInfo = lv_label_create(btnInfo, nullptr);
+ lv_label_set_text_static(txtInfo, "i");
+}
+
+Alarm::~Alarm() {
+ lv_obj_clean(lv_scr_act());
+}
+
+void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
+ using Pinetime::Controllers::AlarmController;
+ if (event == LV_EVENT_CLICKED) {
+ if (obj == btnEnable) {
+ if (alarmController.State() == AlarmController::AlarmState::Alerting) {
+ alarmController.StopAlerting();
+ } else if (alarmController.State() == AlarmController::AlarmState::Set) {
+ alarmController.DisableAlarm();
+ } else {
+ alarmController.ScheduleAlarm();
+ }
+ SetEnableButtonState();
+ return;
+ }
+ if (obj == btnInfo) {
+ ShowInfo();
+ return;
+ }
+ if (obj == btnMessage) {
+ HideInfo();
+ return;
+ }
+ // If any other button was pressed, disable the alarm
+ // this is to make it clear that the alarm won't be set until it is turned back on
+ if (alarmController.State() == AlarmController::AlarmState::Set) {
+ alarmController.DisableAlarm();
+ SetEnableButtonState();
+ }
+ if (obj == btnMinutesUp) {
+ if (alarmMinutes >= 59) {
+ alarmMinutes = 0;
+ } else {
+ alarmMinutes++;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnMinutesDown) {
+ if (alarmMinutes == 0) {
+ alarmMinutes = 59;
+ } else {
+ alarmMinutes--;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnHoursUp) {
+ if (alarmHours >= 23) {
+ alarmHours = 0;
+ } else {
+ alarmHours++;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnHoursDown) {
+ if (alarmHours == 0) {
+ alarmHours = 23;
+ } else {
+ alarmHours--;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnRecur) {
+ ToggleRecurrence();
+ }
+ }
+}
+
+bool Alarm::OnButtonPushed() {
+ if (txtMessage != nullptr && btnMessage != nullptr) {
+ HideInfo();
+ return true;
+ }
+ return false;
+}
+
+void Alarm::UpdateAlarmTime() {
+ lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes);
+ alarmController.SetAlarmTime(alarmHours, alarmMinutes);
+}
+
+void Alarm::SetAlerting() {
+ SetEnableButtonState();
+}
+
+void Alarm::SetEnableButtonState() {
+ switch (alarmController.State()) {
+ case AlarmController::AlarmState::Set:
+ lv_label_set_text(txtEnable, "ON");
+ lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ break;
+ case AlarmController::AlarmState::Not_Set:
+ lv_label_set_text(txtEnable, "OFF");
+ lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+ break;
+ case AlarmController::AlarmState::Alerting:
+ lv_label_set_text(txtEnable, Symbols::stop);
+ lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
+ }
+}
+
+void Alarm::ShowInfo() {
+ btnMessage = lv_btn_create(lv_scr_act(), nullptr);
+ btnMessage->user_data = this;
+ lv_obj_set_event_cb(btnMessage, btnEventHandler);
+ lv_obj_set_height(btnMessage, 200);
+ lv_obj_set_width(btnMessage, 150);
+ lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+ txtMessage = lv_label_create(btnMessage, nullptr);
+ lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
+
+ if (alarmController.State() == AlarmController::AlarmState::Set) {
+ auto timeToAlarm = alarmController.SecondsToAlarm();
+
+ auto daysToAlarm = timeToAlarm / 86400;
+ auto hrsToAlarm = (timeToAlarm % 86400) / 3600;
+ auto minToAlarm = (timeToAlarm % 3600) / 60;
+ auto secToAlarm = timeToAlarm % 60;
+
+ lv_label_set_text_fmt(
+ txtMessage, "Time to\nalarm:\n%2d Days\n%2d Hours\n%2d Minutes\n%2d Seconds", daysToAlarm, hrsToAlarm, minToAlarm, secToAlarm);
+ } else {
+ lv_label_set_text(txtMessage, "Alarm\nis not\nset.");
+ }
+}
+
+void Alarm::HideInfo() {
+ lv_obj_del(btnMessage);
+ txtMessage = nullptr;
+ btnMessage = nullptr;
+}
+
+void Alarm::SetRecurButtonState() {
+ using Pinetime::Controllers::AlarmController;
+ switch (alarmController.Recurrence()) {
+ case AlarmController::RecurType::None:
+ lv_label_set_text(txtRecur, "ONCE");
+ break;
+ case AlarmController::RecurType::Daily:
+ lv_label_set_text(txtRecur, "DAILY");
+ break;
+ case AlarmController::RecurType::Weekdays:
+ lv_label_set_text(txtRecur, "MON-FRI");
+ }
+}
+
+void Alarm::ToggleRecurrence() {
+ using Pinetime::Controllers::AlarmController;
+ switch (alarmController.Recurrence()) {
+ case AlarmController::RecurType::None:
+ alarmController.SetRecurrence(AlarmController::RecurType::Daily);
+ break;
+ case AlarmController::RecurType::Daily:
+ alarmController.SetRecurrence(AlarmController::RecurType::Weekdays);
+ break;
+ case AlarmController::RecurType::Weekdays:
+ alarmController.SetRecurrence(AlarmController::RecurType::None);
+ }
+ SetRecurButtonState();
+}
diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h
new file mode 100644
index 00000000..32a14d2f
--- /dev/null
+++ b/src/displayapp/screens/Alarm.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "Screen.h"
+#include "systemtask/SystemTask.h"
+#include "../LittleVgl.h"
+#include "components/alarm/AlarmController.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Alarm : public Screen {
+ public:
+ Alarm(DisplayApp* app, Controllers::AlarmController& alarmController);
+ ~Alarm() override;
+ void SetAlerting();
+ void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
+ bool OnButtonPushed() override;
+
+ private:
+ bool running;
+ uint8_t alarmHours;
+ uint8_t alarmMinutes;
+ Controllers::AlarmController& alarmController;
+
+ lv_obj_t *time, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown,
+ *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnMessage, *txtMessage, *btnInfo, *txtInfo;
+
+ enum class EnableButtonState { On, Off, Alerting };
+ void SetEnableButtonState();
+ void SetRecurButtonState();
+ void SetAlarm();
+ void ShowInfo();
+ void HideInfo();
+ void ToggleRecurrence();
+ void UpdateAlarmTime();
+ };
+ };
+ };
+}
diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp
index d6c3970b..5c582f60 100644
--- a/src/displayapp/screens/ApplicationList.cpp
+++ b/src/displayapp/screens/ApplicationList.cpp
@@ -34,12 +34,6 @@ ApplicationList::~ApplicationList() {
lv_obj_clean(lv_scr_act());
}
-bool ApplicationList::Refresh() {
- if (running)
- running = screens.Refresh();
- return running;
-}
-
bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}
@@ -64,7 +58,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
{"2", Apps::Twos},
{Symbols::chartLine, Apps::Motion},
{Symbols::drum, Apps::Metronome},
- {"", Apps::None},
+ {Symbols::clock, Apps::Alarm},
}};
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
diff --git a/src/displayapp/screens/ApplicationList.h b/src/displayapp/screens/ApplicationList.h
index 88534ec4..103c38ae 100644
--- a/src/displayapp/screens/ApplicationList.h
+++ b/src/displayapp/screens/ApplicationList.h
@@ -18,7 +18,6 @@ namespace Pinetime {
Pinetime::Controllers::Battery& batteryController,
Controllers::DateTime& dateTimeController);
~ApplicationList() override;
- bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
private:
@@ -33,4 +32,4 @@ namespace Pinetime {
};
}
}
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp
index 0ab47ebf..44ea7f51 100644
--- a/src/displayapp/screens/BatteryInfo.cpp
+++ b/src/displayapp/screens/BatteryInfo.cpp
@@ -4,11 +4,6 @@
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)
: Screen(app), batteryController {batteryController} {
@@ -49,23 +44,21 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
- taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this);
- UpdateScreen();
+ taskRefresh = lv_task_create(RefreshTaskCallback, 5000, LV_TASK_PRIO_MID, this);
+ Refresh();
}
BatteryInfo::~BatteryInfo() {
- lv_task_del(taskUpdate);
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-void BatteryInfo::UpdateScreen() {
-
- batteryController.Update();
+void BatteryInfo::Refresh() {
batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage();
- if (batteryController.IsCharging() and batteryPercent < 100) {
+ if (batteryController.IsCharging()) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text_static(status, "Charging");
} else if (batteryPercent == 100) {
@@ -85,7 +78,3 @@ void BatteryInfo::UpdateScreen() {
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
}
-
-bool BatteryInfo::Refresh() {
- return running;
-}
diff --git a/src/displayapp/screens/BatteryInfo.h b/src/displayapp/screens/BatteryInfo.h
index 69793244..63454a26 100644
--- a/src/displayapp/screens/BatteryInfo.h
+++ b/src/displayapp/screens/BatteryInfo.h
@@ -19,9 +19,7 @@ namespace Pinetime {
BatteryInfo(DisplayApp* app, Pinetime::Controllers::Battery& batteryController);
~BatteryInfo() override;
- bool Refresh() override;
-
- void UpdateScreen();
+ void Refresh() override;
private:
Pinetime::Controllers::Battery& batteryController;
@@ -31,7 +29,7 @@ namespace Pinetime {
lv_obj_t* charging_bar;
lv_obj_t* status;
- lv_task_t* taskUpdate;
+ lv_task_t* taskRefresh;
uint8_t batteryPercent = 0;
uint16_t batteryVoltage = 0;
diff --git a/src/displayapp/screens/Brightness.cpp b/src/displayapp/screens/Brightness.cpp
index 47c10561..1278cd62 100644
--- a/src/displayapp/screens/Brightness.cpp
+++ b/src/displayapp/screens/Brightness.cpp
@@ -30,10 +30,6 @@ Brightness::~Brightness() {
lv_obj_clean(lv_scr_act());
}
-bool Brightness::Refresh() {
- return running;
-}
-
const char* Brightness::LevelToString(Pinetime::Controllers::BrightnessController::Levels level) {
switch (level) {
case Pinetime::Controllers::BrightnessController::Levels::Off:
diff --git a/src/displayapp/screens/Brightness.h b/src/displayapp/screens/Brightness.h
index 9ee33753..14e48592 100644
--- a/src/displayapp/screens/Brightness.h
+++ b/src/displayapp/screens/Brightness.h
@@ -12,7 +12,6 @@ namespace Pinetime {
public:
Brightness(DisplayApp* app, Controllers::BrightnessController& brightness);
~Brightness() override;
- bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
@@ -31,4 +30,4 @@ namespace Pinetime {
};
}
}
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp
index 86afee0c..5a5cd18b 100644
--- a/src/displayapp/screens/Clock.cpp
+++ b/src/displayapp/screens/Clock.cpp
@@ -50,11 +50,6 @@ Clock::~Clock() {
lv_obj_clean(lv_scr_act());
}
-bool Clock::Refresh() {
- screen->Refresh();
- return running;
-}
-
bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screen->OnTouchEvent(event);
}
@@ -83,4 +78,4 @@ std::unique_ptr<Screen> Clock::PineTimeStyleScreen() {
notificatioManager,
settingsController,
motionController);
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h
index 7968cced..648f72da 100644
--- a/src/displayapp/screens/Clock.h
+++ b/src/displayapp/screens/Clock.h
@@ -31,8 +31,6 @@ namespace Pinetime {
Controllers::MotionController& motionController);
~Clock() override;
- bool Refresh() override;
-
bool OnTouchEvent(TouchEvents event) override;
private:
diff --git a/src/displayapp/screens/Error.cpp b/src/displayapp/screens/Error.cpp
new file mode 100644
index 00000000..75946aba
--- /dev/null
+++ b/src/displayapp/screens/Error.cpp
@@ -0,0 +1,50 @@
+#include "Error.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ void ButtonEventCallback(lv_obj_t* obj, lv_event_t /*event*/) {
+ auto* errorScreen = static_cast<Error*>(obj->user_data);
+ errorScreen->ButtonEventHandler();
+ }
+}
+
+Error::Error(Pinetime::Applications::DisplayApp* app, System::BootErrors error)
+ : Screen(app) {
+
+ lv_obj_t* warningLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(warningLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+ lv_label_set_text_static(warningLabel, "Warning");
+ lv_obj_align(warningLabel, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0);
+
+ lv_obj_t* causeLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(causeLabel, LV_LABEL_LONG_BREAK);
+ lv_obj_set_width(causeLabel, LV_HOR_RES);
+ lv_obj_align(causeLabel, warningLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
+
+ if (error == System::BootErrors::TouchController) {
+ lv_label_set_text_static(causeLabel, "Touch controller error detected.");
+ }
+
+ lv_obj_t* tipLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(tipLabel, LV_LABEL_LONG_BREAK);
+ lv_obj_set_width(tipLabel, LV_HOR_RES);
+ lv_label_set_text_static(tipLabel, "If you encounter problems and your device is under warranty, contact the devices seller.");
+ lv_obj_align(tipLabel, causeLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
+
+ btnOk = lv_btn_create(lv_scr_act(), nullptr);
+ btnOk->user_data = this;
+ lv_obj_set_event_cb(btnOk, ButtonEventCallback);
+ lv_obj_set_size(btnOk, LV_HOR_RES, 50);
+ lv_obj_align(btnOk, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_obj_set_style_local_value_str(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Proceed");
+ lv_obj_set_style_local_bg_color(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+}
+
+void Error::ButtonEventHandler() {
+ running = false;
+}
+
+Error::~Error() {
+ lv_obj_clean(lv_scr_act());
+}
diff --git a/src/displayapp/screens/Error.h b/src/displayapp/screens/Error.h
new file mode 100644
index 00000000..20dde7ee
--- /dev/null
+++ b/src/displayapp/screens/Error.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "Screen.h"
+#include "BootErrors.h"
+#include <lvgl/lvgl.h>
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Error : public Screen {
+ public:
+ Error(DisplayApp* app, System::BootErrors error);
+ ~Error() override;
+
+ void ButtonEventHandler();
+ private:
+ lv_obj_t* btnOk;
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/FirmwareUpdate.cpp b/src/displayapp/screens/FirmwareUpdate.cpp
index edb2e49d..79bda0ba 100644
--- a/src/displayapp/screens/FirmwareUpdate.cpp
+++ b/src/displayapp/screens/FirmwareUpdate.cpp
@@ -30,14 +30,16 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime
lv_label_set_text(percentLabel, "Waiting...");
lv_obj_set_auto_realign(percentLabel, true);
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();
}
FirmwareUpdate::~FirmwareUpdate() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool FirmwareUpdate::Refresh() {
+void FirmwareUpdate::Refresh() {
switch (bleController.State()) {
default:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
@@ -73,7 +75,6 @@ bool FirmwareUpdate::Refresh() {
}
break;
}
- return running;
}
void FirmwareUpdate::DisplayProgression() const {
diff --git a/src/displayapp/screens/FirmwareUpdate.h b/src/displayapp/screens/FirmwareUpdate.h
index 90c99f4c..8fc86d8c 100644
--- a/src/displayapp/screens/FirmwareUpdate.h
+++ b/src/displayapp/screens/FirmwareUpdate.h
@@ -16,7 +16,7 @@ namespace Pinetime {
FirmwareUpdate(DisplayApp* app, Pinetime::Controllers::Ble& bleController);
~FirmwareUpdate() override;
- bool Refresh() override;
+ void Refresh() override;
private:
enum class States { Idle, Running, Validated, Error };
@@ -36,6 +36,7 @@ namespace Pinetime {
void UpdateError();
+ lv_task_t* taskRefresh;
TickType_t startTime;
};
}
diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp
index 34a43a9f..eef8f919 100644
--- a/src/displayapp/screens/FirmwareValidation.cpp
+++ b/src/displayapp/screens/FirmwareValidation.cpp
@@ -63,10 +63,6 @@ FirmwareValidation::~FirmwareValidation() {
lv_obj_clean(lv_scr_act());
}
-bool FirmwareValidation::Refresh() {
- return running;
-}
-
void FirmwareValidation::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if (object == buttonValidate && event == LV_EVENT_CLICKED) {
validator.Validate();
diff --git a/src/displayapp/screens/FirmwareValidation.h b/src/displayapp/screens/FirmwareValidation.h
index 1ef5ba0a..bfdb096d 100644
--- a/src/displayapp/screens/FirmwareValidation.h
+++ b/src/displayapp/screens/FirmwareValidation.h
@@ -16,8 +16,6 @@ namespace Pinetime {
FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator);
~FirmwareValidation() override;
- bool Refresh() override;
-
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
private:
diff --git a/src/displayapp/screens/FlashLight.cpp b/src/displayapp/screens/FlashLight.cpp
index 63b2345e..4bc5b558 100644
--- a/src/displayapp/screens/FlashLight.cpp
+++ b/src/displayapp/screens/FlashLight.cpp
@@ -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) {
return false;
}
diff --git a/src/displayapp/screens/FlashLight.h b/src/displayapp/screens/FlashLight.h
index a862ffdb..7f5ca6c5 100644
--- a/src/displayapp/screens/FlashLight.h
+++ b/src/displayapp/screens/FlashLight.h
@@ -16,8 +16,6 @@ namespace Pinetime {
FlashLight(DisplayApp* app, System::SystemTask& systemTask, Controllers::BrightnessController& brightness);
~FlashLight() override;
- bool Refresh() override;
-
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp
index 5689b63e..b6ece27f 100644
--- a/src/displayapp/screens/HeartRate.cpp
+++ b/src/displayapp/screens/HeartRate.cpp
@@ -64,14 +64,17 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
UpdateStartStopButton(isHrRunning);
if (isHrRunning)
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
}
HeartRate::~HeartRate() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
-bool HeartRate::Refresh() {
+void HeartRate::Refresh() {
auto state = heartRateController.State();
switch (state) {
@@ -86,8 +89,6 @@ bool HeartRate::Refresh() {
lv_label_set_text(label_status, ToString(state));
lv_obj_align(label_status, label_hr, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
-
- return running;
}
void HeartRate::OnStartStopEvent(lv_event_t event) {
diff --git a/src/displayapp/screens/HeartRate.h b/src/displayapp/screens/HeartRate.h
index a23c5af8..7f7d3ad3 100644
--- a/src/displayapp/screens/HeartRate.h
+++ b/src/displayapp/screens/HeartRate.h
@@ -20,7 +20,7 @@ namespace Pinetime {
HeartRate(DisplayApp* app, Controllers::HeartRateController& HeartRateController, System::SystemTask& systemTask);
~HeartRate() override;
- bool Refresh() override;
+ void Refresh() override;
void OnStartStopEvent(lv_event_t event);
@@ -33,6 +33,8 @@ namespace Pinetime {
lv_obj_t* label_status;
lv_obj_t* btn_startStop;
lv_obj_t* label_startStop;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/InfiniPaint.cpp b/src/displayapp/screens/InfiniPaint.cpp
index 58bfa558..85a5e826 100644
--- a/src/displayapp/screens/InfiniPaint.cpp
+++ b/src/displayapp/screens/InfiniPaint.cpp
@@ -12,10 +12,6 @@ InfiniPaint::~InfiniPaint() {
lv_obj_clean(lv_scr_act());
}
-bool InfiniPaint::Refresh() {
- return running;
-}
-
bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
switch (event) {
case Pinetime::Applications::TouchEvents::LongTap:
diff --git a/src/displayapp/screens/InfiniPaint.h b/src/displayapp/screens/InfiniPaint.h
index 6251752a..0a70e033 100644
--- a/src/displayapp/screens/InfiniPaint.h
+++ b/src/displayapp/screens/InfiniPaint.h
@@ -17,8 +17,6 @@ namespace Pinetime {
~InfiniPaint() override;
- bool Refresh() override;
-
bool OnTouchEvent(TouchEvents event) override;
bool OnTouchEvent(uint16_t x, uint16_t y) override;
diff --git a/src/displayapp/screens/Label.cpp b/src/displayapp/screens/Label.cpp
index f724fd48..1761a7b5 100644
--- a/src/displayapp/screens/Label.cpp
+++ b/src/displayapp/screens/Label.cpp
@@ -36,7 +36,3 @@ Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::Displ
Label::~Label() {
lv_obj_clean(lv_scr_act());
}
-
-bool Label::Refresh() {
- return running;
-}
diff --git a/src/displayapp/screens/Label.h b/src/displayapp/screens/Label.h
index 834f8c88..f1e49079 100644
--- a/src/displayapp/screens/Label.h
+++ b/src/displayapp/screens/Label.h
@@ -12,8 +12,6 @@ namespace Pinetime {
Label(uint8_t screenID, uint8_t numScreens, DisplayApp* app, lv_obj_t* labelText);
~Label() override;
- bool Refresh() override;
-
private:
lv_obj_t* labelText = nullptr;
lv_point_t pageIndicatorBasePoints[2];
diff --git a/src/displayapp/screens/List.cpp b/src/displayapp/screens/List.cpp
index 91cab9f0..064b47a6 100644
--- a/src/displayapp/screens/List.cpp
+++ b/src/displayapp/screens/List.cpp
@@ -98,11 +98,6 @@ List::~List() {
lv_obj_clean(lv_scr_act());
}
-bool List::Refresh() {
-
- return running;
-}
-
void List::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
for (int i = 0; i < MAXLISTITEMS; i++) {
diff --git a/src/displayapp/screens/List.h b/src/displayapp/screens/List.h
index a45fd1d3..d9f61f29 100644
--- a/src/displayapp/screens/List.h
+++ b/src/displayapp/screens/List.h
@@ -27,8 +27,6 @@ namespace Pinetime {
std::array<Applications, MAXLISTITEMS>& applications);
~List() override;
- bool Refresh() override;
-
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
private:
diff --git a/src/displayapp/screens/Meter.cpp b/src/displayapp/screens/Meter.cpp
index e0dbdfad..57cde9cf 100644
--- a/src/displayapp/screens/Meter.cpp
+++ b/src/displayapp/screens/Meter.cpp
@@ -20,17 +20,17 @@ Meter::Meter(Pinetime::Applications::DisplayApp* app) : Screen(app) {
lv_obj_set_size(lmeter, 200, 200);
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() {
-
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool Meter::Refresh() {
+void Meter::Refresh() {
lv_linemeter_set_value(lmeter, value++); /*Set the current value*/
if (value >= 60)
value = 0;
-
- return running;
}
diff --git a/src/displayapp/screens/Meter.h b/src/displayapp/screens/Meter.h
index 24af15ad..9b3d1d48 100644
--- a/src/displayapp/screens/Meter.h
+++ b/src/displayapp/screens/Meter.h
@@ -14,13 +14,15 @@ namespace Pinetime {
Meter(DisplayApp* app);
~Meter() override;
- bool Refresh() override;
+ void Refresh() override;
private:
lv_style_t style_lmeter;
lv_obj_t* lmeter;
uint32_t value = 0;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp
index 5fbe5f36..52cb8519 100644
--- a/src/displayapp/screens/Metronome.cpp
+++ b/src/displayapp/screens/Metronome.cpp
@@ -66,16 +66,19 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl
lv_obj_set_size(playPause, 115, 50);
lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play);
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
Metronome::~Metronome() {
+ lv_task_del(taskRefresh);
systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
-bool Metronome::Refresh() {
+void Metronome::Refresh() {
if (metronomeStarted) {
- if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) {
+ if (xTaskGetTickCount() - startTime > 60u * configTICK_RATE_HZ / static_cast<uint16_t>(bpm)) {
startTime += 60 * configTICK_RATE_HZ / bpm;
counter--;
if (counter == 0) {
@@ -86,7 +89,6 @@ bool Metronome::Refresh() {
}
}
}
- return running;
}
void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
diff --git a/src/displayapp/screens/Metronome.h b/src/displayapp/screens/Metronome.h
index a4baa096..f3a84dc8 100644
--- a/src/displayapp/screens/Metronome.h
+++ b/src/displayapp/screens/Metronome.h
@@ -11,7 +11,7 @@ namespace Pinetime {
public:
Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask);
~Metronome() override;
- bool Refresh() override;
+ void Refresh() override;
void OnEvent(lv_obj_t* obj, lv_event_t event);
private:
@@ -28,6 +28,8 @@ namespace Pinetime {
lv_obj_t *bpmArc, *bpmTap, *bpmValue;
lv_obj_t *bpbDropdown, *currentBpbText;
lv_obj_t *playPause;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp
index 43a5575e..2f1f7c21 100644
--- a/src/displayapp/screens/Motion.cpp
+++ b/src/displayapp/screens/Motion.cpp
@@ -36,13 +36,16 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr
labelStep = lv_label_create(lv_scr_act(), NULL);
lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_label_set_text(labelStep, "Steps ---");
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
Motion::~Motion() {
+ lv_task_del(taskRefresh);
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, ser2, motionController.Y());
lv_chart_set_next(chart, ser3, motionController.Z());
@@ -55,6 +58,4 @@ bool Motion::Refresh() {
motionController.Y() / 0x10,
motionController.Z() / 0x10);
lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
-
- return running;
}
diff --git a/src/displayapp/screens/Motion.h b/src/displayapp/screens/Motion.h
index 7e65197b..20a18d02 100644
--- a/src/displayapp/screens/Motion.h
+++ b/src/displayapp/screens/Motion.h
@@ -17,7 +17,7 @@ namespace Pinetime {
Motion(DisplayApp* app, Controllers::MotionController& motionController);
~Motion() override;
- bool Refresh() override;
+ void Refresh() override;
private:
Controllers::MotionController& motionController;
@@ -28,6 +28,7 @@ namespace Pinetime {
lv_obj_t* label;
lv_obj_t* labelStep;
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 257e9aea..47ddb655 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -139,14 +139,17 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
frameB = false;
musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN);
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
Music::~Music() {
+ lv_task_del(taskRefresh);
lv_style_reset(&btn_style);
lv_obj_clean(lv_scr_act());
}
-bool Music::Refresh() {
+void Music::Refresh() {
if (artist != musicService.getArtist()) {
artist = musicService.getArtist();
currentLength = 0;
@@ -210,8 +213,6 @@ bool Music::Refresh() {
} else {
lv_label_set_text(txtPlayPause, Symbols::play);
}
-
- return running;
}
void Music::UpdateLength() {
diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h
index 00d3ad92..6f2d80a0 100644
--- a/src/displayapp/screens/Music.h
+++ b/src/displayapp/screens/Music.h
@@ -35,7 +35,7 @@ namespace Pinetime {
~Music() override;
- bool Refresh() override;
+ void Refresh() override;
void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
@@ -79,6 +79,8 @@ namespace Pinetime {
bool playing;
+ lv_task_t* taskRefresh;
+
/** Watchapp */
};
}
diff --git a/src/displayapp/screens/Navigation.cpp b/src/displayapp/screens/Navigation.cpp
index 79b04e21..d437cc6d 100644
--- a/src/displayapp/screens/Navigation.cpp
+++ b/src/displayapp/screens/Navigation.cpp
@@ -161,13 +161,16 @@ Navigation::Navigation(Pinetime::Applications::DisplayApp* app, Pinetime::Contro
lv_bar_set_anim_time(barProgress, 500);
lv_bar_set_range(barProgress, 0, 100);
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() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool Navigation::Refresh() {
+void Navigation::Refresh() {
if (flag != navService.getFlag()) {
flag = navService.getFlag();
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);
}
}
-
- return running;
}
-
-
diff --git a/src/displayapp/screens/Navigation.h b/src/displayapp/screens/Navigation.h
index eb7e00c4..48f00a76 100644
--- a/src/displayapp/screens/Navigation.h
+++ b/src/displayapp/screens/Navigation.h
@@ -35,7 +35,7 @@ namespace Pinetime {
Navigation(DisplayApp* app, Pinetime::Controllers::NavigationService& nav);
~Navigation() override;
- bool Refresh() override;
+ void Refresh() override;
private:
lv_obj_t* imgFlag;
@@ -49,6 +49,8 @@ namespace Pinetime {
std::string narrative;
std::string manDist;
int progress;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp
index c061c146..4f475813 100644
--- a/src/displayapp/screens/Notifications.cpp
+++ b/src/displayapp/screens/Notifications.cpp
@@ -52,15 +52,18 @@ Notifications::Notifications(DisplayApp* app,
timeoutTickCountEnd = timeoutTickCountStart + (5 * 1024);
}
}
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
Notifications::~Notifications() {
+ lv_task_del(taskRefresh);
// make sure we stop any vibrations before exiting
Controllers::MotorController::StopRinging();
lv_obj_clean(lv_scr_act());
}
-bool Notifications::Refresh() {
+void Notifications::Refresh() {
if (mode == Modes::Preview && timeoutLine != nullptr) {
auto tick = xTaskGetTickCount();
int32_t pos = 240 - ((tick - timeoutTickCountStart) / ((timeoutTickCountEnd - timeoutTickCountStart) / 240));
@@ -70,7 +73,6 @@ bool Notifications::Refresh() {
timeoutLinePoints[1].x = pos;
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
}
- return running && currentItem->IsRunning();
}
bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
@@ -127,10 +129,6 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
alertNotificationService);
}
return true;
- case Pinetime::Applications::TouchEvents::LongTap: {
- // notificationManager.ToggleVibrations();
- return true;
- }
default:
return false;
}
@@ -150,7 +148,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
uint8_t notifNb,
Modes mode,
Pinetime::Controllers::AlertNotificationService& alertNotificationService)
- : notifNr {notifNr}, notifNb {notifNb}, mode {mode}, alertNotificationService {alertNotificationService} {
+ : mode {mode}, alertNotificationService {alertNotificationService} {
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));
diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h
index a02d9b46..0b5271e7 100644
--- a/src/displayapp/screens/Notifications.h
+++ b/src/displayapp/screens/Notifications.h
@@ -24,7 +24,7 @@ namespace Pinetime {
Modes mode);
~Notifications() override;
- bool Refresh() override;
+ void Refresh() override;
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
class NotificationItem {
@@ -43,21 +43,13 @@ namespace Pinetime {
void OnCallButtonEvent(lv_obj_t*, lv_event_t event);
private:
- uint8_t notifNr = 0;
- uint8_t notifNb = 0;
- char pageText[4];
-
lv_obj_t* container1;
- lv_obj_t* t1;
- lv_obj_t* l1;
- lv_obj_t* l2;
lv_obj_t* bt_accept;
lv_obj_t* bt_mute;
lv_obj_t* bt_reject;
lv_obj_t* label_accept;
lv_obj_t* label_mute;
lv_obj_t* label_reject;
- lv_obj_t* bottomPlaceholder;
Modes mode;
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
bool running = true;
@@ -79,6 +71,8 @@ namespace Pinetime {
lv_obj_t* timeoutLine = nullptr;
uint32_t timeoutTickCountStart;
uint32_t timeoutTickCountEnd;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp
index 79e0c3d3..26c2368b 100644
--- a/src/displayapp/screens/Paddle.cpp
+++ b/src/displayapp/screens/Paddle.cpp
@@ -27,13 +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_radius(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_size(ball, ballSize, ballSize);
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
Paddle::~Paddle() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool Paddle::Refresh() {
+void Paddle::Refresh() {
ballX += dx;
ballY += dy;
@@ -44,8 +47,8 @@ bool Paddle::Refresh() {
dy *= -1;
}
- // checks if it has touched the side (left side)
- if (ballX >= LV_VER_RES - ballSize - 1) {
+ // checks if it has touched the side (right side)
+ if (ballX >= LV_HOR_RES - ballSize - 1) {
dx *= -1;
}
@@ -65,7 +68,6 @@ bool Paddle::Refresh() {
}
}
lv_label_set_text_fmt(points, "%04d", score);
- return running;
}
bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
diff --git a/src/displayapp/screens/Paddle.h b/src/displayapp/screens/Paddle.h
index 30ab8f94..fc2131a1 100644
--- a/src/displayapp/screens/Paddle.h
+++ b/src/displayapp/screens/Paddle.h
@@ -16,7 +16,7 @@ namespace Pinetime {
Paddle(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl);
~Paddle() override;
- bool Refresh() override;
+ void Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
bool OnTouchEvent(uint16_t x, uint16_t y) override;
@@ -40,6 +40,8 @@ namespace Pinetime {
lv_obj_t* paddle;
lv_obj_t* ball;
lv_obj_t* background;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp
index 98fd976c..fa88d459 100644
--- a/src/displayapp/screens/PineTimeStyle.cpp
+++ b/src/displayapp/screens/PineTimeStyle.cpp
@@ -1,5 +1,5 @@
/*
- * This file is part of the Infinitime distribution (https://github.com/JF002/Infinitime).
+ * This file is part of the Infinitime distribution (https://github.com/InfiniTimeOrg/Infinitime).
* Copyright (c) 2021 Kieran Cawthray.
*
* This program is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
#include <date/date.h>
#include <lvgl/lvgl.h>
#include <cstdio>
+#include <displayapp/Colors.h>
#include "BatteryIcon.h"
#include "BleIcon.h"
#include "NotificationIcon.h"
@@ -51,7 +52,8 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
notificatioManager {notificatioManager},
settingsController {settingsController},
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);
displayedChar[0] = 0;
@@ -60,48 +62,45 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
displayedChar[3] = 0;
displayedChar[4] = 0;
- /* Create a 200px wide background rectangle */
+ //Create a 200px wide background rectangle
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_size(timebar, 200, 240);
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);
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_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
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_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_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
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_label_set_text(timeAMPM, "");
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);
- 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_size(sidebar, 40, 240);
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);
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_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
-
- batteryPlug = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_align(batteryPlug, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
+ lv_obj_set_auto_realign(batteryIcon, true);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
@@ -111,7 +110,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_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 40);
- /* Calendar icon */
+ // Calendar icon
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_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
@@ -148,7 +147,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
lv_obj_set_size(calendarCrossBar2, 8, 3);
lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
- /* Display date */
+ // Display date
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_label_set_text(dateDayOfWeek, "THU");
@@ -184,7 +183,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_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_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);
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
@@ -193,24 +192,34 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text(backgroundLabel, "");
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
+ Refresh();
}
PineTimeStyle::~PineTimeStyle() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool PineTimeStyle::Refresh() {
- batteryPercentRemaining = batteryController.PercentRemaining();
- if (batteryPercentRemaining.IsUpdated()) {
- auto batteryPercent = batteryPercentRemaining.Get();
- if (batteryController.IsCharging()) {
- auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
- lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
- lv_obj_realign(batteryPlug);
- lv_label_set_text(batteryIcon, "");
+void PineTimeStyle::SetBatteryIcon() {
+ auto batteryPercent = batteryPercentRemaining.Get();
+ lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+}
+
+void PineTimeStyle::Refresh() {
+ isCharging = batteryController.IsCharging();
+ if (isCharging.IsUpdated()) {
+ if (isCharging.Get()) {
+ lv_label_set_text(batteryIcon, Symbols::plug);
} else {
- lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
- lv_label_set_text(batteryPlug, "");
+ SetBatteryIcon();
+ }
+ }
+ if (!isCharging.Get()) {
+ batteryPercentRemaining = batteryController.PercentRemaining();
+ if (batteryPercentRemaining.IsUpdated()) {
+ SetBatteryIcon();
}
}
@@ -303,6 +312,4 @@ bool PineTimeStyle::Refresh() {
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
}
-
- return running;
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h
index f4cd28e4..ba473806 100644
--- a/src/displayapp/screens/PineTimeStyle.h
+++ b/src/displayapp/screens/PineTimeStyle.h
@@ -30,7 +30,7 @@ namespace Pinetime {
Controllers::MotionController& motionController);
~PineTimeStyle() override;
- bool Refresh() override;
+ void Refresh() override;
private:
char displayedChar[5];
@@ -41,6 +41,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
+ DirtyValue<bool> isCharging {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};
@@ -58,7 +59,6 @@ namespace Pinetime {
lv_obj_t* backgroundLabel;
lv_obj_t* batteryIcon;
lv_obj_t* bleIcon;
- lv_obj_t* batteryPlug;
lv_obj_t* calendarOuter;
lv_obj_t* calendarInner;
lv_obj_t* calendarBar1;
@@ -75,6 +75,10 @@ namespace Pinetime {
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
+
+ void SetBatteryIcon();
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/Screen.cpp b/src/displayapp/screens/Screen.cpp
index 1467df33..6ae5b7bb 100644
--- a/src/displayapp/screens/Screen.cpp
+++ b/src/displayapp/screens/Screen.cpp
@@ -1,2 +1,6 @@
#include "Screen.h"
-using namespace Pinetime::Applications::Screens; \ No newline at end of file
+using namespace Pinetime::Applications::Screens;
+
+void Screen::RefreshTaskCallback(lv_task_t* task) {
+ static_cast<Screen*>(task->user_data)->Refresh();
+}
diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h
index 420f2015..ce5741b2 100644
--- a/src/displayapp/screens/Screen.h
+++ b/src/displayapp/screens/Screen.h
@@ -2,6 +2,7 @@
#include <cstdint>
#include "../TouchEvents.h"
+#include <lvgl/lvgl.h>
namespace Pinetime {
namespace Applications {
@@ -38,25 +39,20 @@ namespace Pinetime {
};
class Screen {
+ private:
+ virtual void Refresh() {
+ }
+
public:
explicit Screen(DisplayApp* app) : app {app} {
}
virtual ~Screen() = default;
- /**
- * 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.
- *
- * 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;
+ static void RefreshTaskCallback(lv_task_t* task);
+
+ bool IsRunning() const {
+ return running;
+ }
/** @return false if the button hasn't been handled by the app, true if it has been handled */
virtual bool OnButtonPushed() {
diff --git a/src/displayapp/screens/ScreenList.h b/src/displayapp/screens/ScreenList.h
index 50d66328..a9d747aa 100644
--- a/src/displayapp/screens/ScreenList.h
+++ b/src/displayapp/screens/ScreenList.h
@@ -30,11 +30,6 @@ namespace Pinetime {
lv_obj_clean(lv_scr_act());
}
- bool Refresh() override {
- running = current->Refresh();
- return running;
- }
-
bool OnTouchEvent(TouchEvents event) override {
if (mode == ScreenListModes::UpDown) {
diff --git a/src/displayapp/screens/Steps.cpp b/src/displayapp/screens/Steps.cpp
index d72e8333..c41163ab 100644
--- a/src/displayapp/screens/Steps.cpp
+++ b/src/displayapp/screens/Steps.cpp
@@ -47,20 +47,20 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
}
Steps::~Steps() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool Steps::Refresh() {
-
+void Steps::Refresh() {
stepsCount = motionController.NbSteps();
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
-
- return running;
}
diff --git a/src/displayapp/screens/Steps.h b/src/displayapp/screens/Steps.h
index 9c135e26..d7cf31e1 100644
--- a/src/displayapp/screens/Steps.h
+++ b/src/displayapp/screens/Steps.h
@@ -15,24 +15,23 @@ namespace Pinetime {
namespace Screens {
class Steps : public Screen {
- public:
- Steps(DisplayApp* app, Controllers::MotionController& motionController, Controllers::Settings &settingsController);
- ~Steps() override;
+ public:
+ Steps(DisplayApp* app, Controllers::MotionController& motionController, Controllers::Settings& settingsController);
+ ~Steps() override;
- bool Refresh() override;
-
+ void Refresh() override;
- private:
+ private:
+ Controllers::MotionController& motionController;
+ Controllers::Settings& settingsController;
- Controllers::MotionController& motionController;
- Controllers::Settings& settingsController;
+ lv_obj_t* lSteps;
+ lv_obj_t* lStepsIcon;
+ lv_obj_t* stepsArc;
- lv_obj_t * lSteps;
- lv_obj_t * lStepsIcon;
- lv_obj_t * stepsArc;
-
- uint32_t stepsCount;
+ uint32_t stepsCount;
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp
index e3db6299..9b27a89d 100644
--- a/src/displayapp/screens/StopWatch.cpp
+++ b/src/displayapp/screens/StopWatch.cpp
@@ -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)
: Screen(app),
systemTask {systemTask},
- running {true},
currentState {States::Init},
startTime {},
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_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55);
lv_label_set_text(lapTwoText, "");
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
StopWatch::~StopWatch() {
+ lv_task_del(taskRefresh);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
@@ -149,7 +151,7 @@ void StopWatch::pause() {
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
-bool StopWatch::Refresh() {
+void StopWatch::Refresh() {
if (currentState == States::Running) {
timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
@@ -157,7 +159,6 @@ bool StopWatch::Refresh() {
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
}
- return running;
}
void StopWatch::playPauseBtnEventHandler(lv_event_t event) {
@@ -196,8 +197,7 @@ void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
bool StopWatch::OnButtonPushed() {
if (currentState == States::Running) {
pause();
- } else {
- running = false;
+ return true;
}
- return true;
+ return false;
}
diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h
index e132f158..25634e92 100644
--- a/src/displayapp/screens/StopWatch.h
+++ b/src/displayapp/screens/StopWatch.h
@@ -64,7 +64,7 @@ namespace Pinetime::Applications::Screens {
public:
StopWatch(DisplayApp* app, System::SystemTask& systemTask);
~StopWatch() override;
- bool Refresh() override;
+ void Refresh() override;
void playPauseBtnEventHandler(lv_event_t event);
void stopLapBtnEventHandler(lv_event_t event);
@@ -77,7 +77,6 @@ namespace Pinetime::Applications::Screens {
private:
Pinetime::System::SystemTask& systemTask;
TickType_t timeElapsed;
- bool running;
States currentState;
TickType_t startTime;
TickType_t oldTimeElapsed;
@@ -86,5 +85,7 @@ namespace Pinetime::Applications::Screens {
int lapNr = 0;
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
lv_obj_t *lapOneText, *lapTwoText;
+
+ lv_task_t* taskRefresh;
};
}
diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index ad758a8b..343b72bf 100644
--- a/src/displayapp/screens/SystemInfo.cpp
+++ b/src/displayapp/screens/SystemInfo.cpp
@@ -33,7 +33,8 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::WatchdogView& watchdog,
- Pinetime::Controllers::MotionController& motionController)
+ Pinetime::Controllers::MotionController& motionController,
+ Pinetime::Drivers::Cst816S& touchPanel)
: Screen(app),
dateTimeController {dateTimeController},
batteryController {batteryController},
@@ -41,6 +42,7 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
bleController {bleController},
watchdog {watchdog},
motionController{motionController},
+ touchPanel{touchPanel},
screens {app,
0,
{[this]() -> std::unique_ptr<Screen> {
@@ -65,13 +67,6 @@ SystemInfo::~SystemInfo() {
lv_obj_clean(lv_scr_act());
}
-bool SystemInfo::Refresh() {
- if (running) {
- screens.Refresh();
- }
- return running;
-}
-
bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}
@@ -148,7 +143,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
"#444444 Battery# %d%%/%03imV\n"
"#444444 Backlight# %s\n"
"#444444 Last reset# %s\n"
- "#444444 Accel.# %s\n",
+ "#444444 Accel.# %s\n"
+ "#444444 Touch.# %x.%x.%x\n",
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Year(),
@@ -163,7 +159,10 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
batteryController.Voltage(),
brightnessController.ToString(),
resetReason,
- ToString(motionController.DeviceType()));
+ ToString(motionController.DeviceType()),
+ touchPanel.GetChipId(),
+ touchPanel.GetVendorId(),
+ touchPanel.GetFwVersion());
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::make_unique<Screens::Label>(1, 5, app, label);
}
@@ -271,7 +270,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen5() {
"Public License v3\n"
"#444444 Source code#\n"
"#FFFF00 https://github.com/#\n"
- "#FFFF00 JF002/InfiniTime#");
+ "#FFFF00 InfiniTimeOrg/#\n"
+ "#FFFF00 InfiniTime#");
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::make_unique<Screens::Label>(4, 5, app, label);
diff --git a/src/displayapp/screens/SystemInfo.h b/src/displayapp/screens/SystemInfo.h
index a9ad652d..bfcc3aa4 100644
--- a/src/displayapp/screens/SystemInfo.h
+++ b/src/displayapp/screens/SystemInfo.h
@@ -28,9 +28,9 @@ namespace Pinetime {
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::WatchdogView& watchdog,
- Pinetime::Controllers::MotionController& motionController);
+ Pinetime::Controllers::MotionController& motionController,
+ Pinetime::Drivers::Cst816S& touchPanel);
~SystemInfo() override;
- bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
private:
@@ -40,6 +40,7 @@ namespace Pinetime {
Pinetime::Controllers::Ble& bleController;
Pinetime::Drivers::WatchdogView& watchdog;
Pinetime::Controllers::MotionController& motionController;
+ Pinetime::Drivers::Cst816S& touchPanel;
ScreenList<5> screens;
diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp
index 2ffbfbc2..1d4f0d0e 100644
--- a/src/displayapp/screens/Tile.cpp
+++ b/src/displayapp/screens/Tile.cpp
@@ -123,10 +123,6 @@ void Tile::UpdateScreen() {
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryController.PercentRemaining()));
}
-bool Tile::Refresh() {
- return running;
-}
-
void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) {
if(obj != btnm1) return;
diff --git a/src/displayapp/screens/Tile.h b/src/displayapp/screens/Tile.h
index 765a8def..83d3fdf5 100644
--- a/src/displayapp/screens/Tile.h
+++ b/src/displayapp/screens/Tile.h
@@ -30,7 +30,6 @@ namespace Pinetime {
~Tile() override;
- bool Refresh() override;
void UpdateScreen();
void OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId);
diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp
index 99e979ba..ff3099d5 100644
--- a/src/displayapp/screens/Timer.cpp
+++ b/src/displayapp/screens/Timer.cpp
@@ -4,10 +4,8 @@
#include "Symbols.h"
#include "lvgl/lvgl.h"
-
using namespace Pinetime::Applications::Screens;
-
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
Timer* screen = static_cast<Timer*>(obj->user_data);
screen->OnButtonEvent(obj, event);
@@ -22,7 +20,7 @@ void Timer::createButtons() {
lv_obj_set_width(btnMinutesUp, 60);
txtMUp = lv_label_create(btnMinutesUp, nullptr);
lv_label_set_text(txtMUp, "+");
-
+
btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesDown->user_data = this;
lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
@@ -31,7 +29,7 @@ void Timer::createButtons() {
lv_obj_set_width(btnMinutesDown, 60);
txtMDown = lv_label_create(btnMinutesDown, nullptr);
lv_label_set_text(txtMDown, "-");
-
+
btnSecondsUp = lv_btn_create(lv_scr_act(), nullptr);
btnSecondsUp->user_data = this;
lv_obj_set_event_cb(btnSecondsUp, btnEventHandler);
@@ -40,7 +38,7 @@ void Timer::createButtons() {
lv_obj_set_width(btnSecondsUp, 60);
txtSUp = lv_label_create(btnSecondsUp, nullptr);
lv_label_set_text(txtSUp, "+");
-
+
btnSecondsDown = lv_btn_create(lv_scr_act(), nullptr);
btnSecondsDown->user_data = this;
lv_obj_set_event_cb(btnSecondsDown, btnEventHandler);
@@ -49,24 +47,20 @@ void Timer::createButtons() {
lv_obj_set_width(btnSecondsDown, 60);
txtSDown = lv_label_create(btnSecondsDown, nullptr);
lv_label_set_text(txtSDown, "-");
-
}
-
Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController)
- : Screen(app),
- running{true},
- timerController{timerController} {
-
+ : Screen(app), running {true}, timerController {timerController} {
+
time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
-
+
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60);
lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20);
-
+
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
btnPlayPause->user_data = this;
lv_obj_set_event_cb(btnPlayPause, btnEventHandler);
@@ -79,20 +73,20 @@ Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController)
lv_label_set_text(txtPlayPause, Symbols::play);
createButtons();
}
-
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
Timer::~Timer() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
-
}
-bool Timer::Refresh() {
+void Timer::Refresh() {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60);
}
- return running;
}
void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
@@ -105,11 +99,11 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
secondsToSet = seconds % 60;
timerController.StopTimer();
createButtons();
-
+
} else if (secondsToSet + minutesToSet > 0) {
lv_label_set_text(txtPlayPause, Symbols::pause);
timerController.StartTimer((secondsToSet + minutesToSet * 60) * 1000);
-
+
lv_obj_del(btnSecondsDown);
btnSecondsDown = nullptr;
lv_obj_del(btnSecondsUp);
@@ -118,7 +112,6 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
btnMinutesDown = nullptr;
lv_obj_del(btnMinutesUp);
btnMinutesUp = nullptr;
-
}
} else {
if (!timerController.IsRunning()) {
@@ -129,7 +122,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
minutesToSet++;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
-
+
} else if (obj == btnMinutesDown) {
if (minutesToSet == 0) {
minutesToSet = 59;
@@ -137,7 +130,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
minutesToSet--;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
-
+
} else if (obj == btnSecondsUp) {
if (secondsToSet >= 59) {
secondsToSet = 0;
@@ -145,7 +138,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
secondsToSet++;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
-
+
} else if (obj == btnSecondsDown) {
if (secondsToSet == 0) {
secondsToSet = 59;
@@ -153,21 +146,16 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
secondsToSet--;
}
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
-
}
}
-
}
-
}
-
}
-
void Timer::setDone() {
lv_label_set_text(time, "00:00");
lv_label_set_text(txtPlayPause, Symbols::play);
secondsToSet = 0;
minutesToSet = 0;
createButtons();
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h
index 0d66f2d4..d0fc8ed1 100644
--- a/src/displayapp/screens/Timer.h
+++ b/src/displayapp/screens/Timer.h
@@ -8,35 +8,32 @@
#include "components/timer/TimerController.h"
namespace Pinetime::Applications::Screens {
-
-
+
class Timer : public Screen {
public:
-
- enum class Modes {
- Normal, Done
- };
-
+ enum class Modes { Normal, Done };
+
Timer(DisplayApp* app, Controllers::TimerController& timerController);
-
+
~Timer() override;
-
- bool Refresh() override;
-
+
+ void Refresh() override;
+
void setDone();
-
+
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
-
+
private:
-
bool running;
uint8_t secondsToSet = 0;
uint8_t minutesToSet = 0;
Controllers::TimerController& timerController;
-
+
void createButtons();
-
- lv_obj_t* time, * msecTime, * btnPlayPause, * txtPlayPause, * btnMinutesUp, * btnMinutesDown, * btnSecondsUp, * btnSecondsDown, * txtMUp,
- * txtMDown, * txtSUp, * txtSDown;
+
+ lv_obj_t *time, *msecTime, *btnPlayPause, *txtPlayPause, *btnMinutesUp, *btnMinutesDown, *btnSecondsUp, *btnSecondsDown, *txtMUp,
+ *txtMDown, *txtSUp, *txtSDown;
+
+ lv_task_t* taskRefresh;
};
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/Twos.cpp b/src/displayapp/screens/Twos.cpp
index eb268077..4201d501 100644
--- a/src/displayapp/screens/Twos.cpp
+++ b/src/displayapp/screens/Twos.cpp
@@ -102,10 +102,6 @@ Twos::~Twos() {
lv_obj_clean(lv_scr_act());
}
-bool Twos::Refresh() {
- return running;
-}
-
bool Twos::placeNewTile() {
std::vector<std::pair<int, int>> availableCells;
for (int row = 0; row < 4; row++) {
@@ -295,4 +291,4 @@ void Twos::updateGridDisplay(Tile grid[][4]) {
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/Twos.h b/src/displayapp/screens/Twos.h
index 3367618f..6d85cff6 100644
--- a/src/displayapp/screens/Twos.h
+++ b/src/displayapp/screens/Twos.h
@@ -14,7 +14,6 @@ namespace Pinetime {
public:
Twos(DisplayApp* app);
~Twos() override;
- bool Refresh() override;
bool OnTouchEvent(TouchEvents event) override;
@@ -36,4 +35,4 @@ namespace Pinetime {
};
}
}
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp
index 1410fc28..53e7faf7 100644
--- a/src/displayapp/screens/WatchFaceAnalog.cpp
+++ b/src/displayapp/screens/WatchFaceAnalog.cpp
@@ -68,6 +68,7 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text(batteryIcon, Symbols::batteryHalf);
lv_obj_align(batteryIcon, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
+ lv_obj_set_auto_realign(batteryIcon, true);
notificationIcon = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
@@ -118,10 +119,13 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false);
lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace);
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
UpdateClock();
}
WatchFaceAnalog::~WatchFaceAnalog() {
+ lv_task_del(taskRefresh);
+
lv_style_reset(&hour_line_style);
lv_style_reset(&hour_line_style_trace);
lv_style_reset(&minute_line_style);
@@ -173,11 +177,31 @@ void WatchFaceAnalog::UpdateClock() {
}
}
-bool WatchFaceAnalog::Refresh() {
- batteryPercentRemaining = batteryController.PercentRemaining();
- if (batteryPercentRemaining.IsUpdated()) {
- auto batteryPercent = batteryPercentRemaining.Get();
- lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+void WatchFaceAnalog::SetBatteryIcon() {
+ auto batteryPercent = batteryPercentRemaining.Get();
+ if (batteryPercent == 100) {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ } else {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ }
+ lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+}
+
+void WatchFaceAnalog::Refresh() {
+ isCharging = batteryController.IsCharging();
+ if (isCharging.IsUpdated()) {
+ if (isCharging.Get()) {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
+ lv_label_set_text(batteryIcon, Symbols::plug);
+ } else {
+ SetBatteryIcon();
+ }
+ }
+ if (!isCharging.Get()) {
+ batteryPercentRemaining = batteryController.PercentRemaining();
+ if (batteryPercentRemaining.IsUpdated()) {
+ SetBatteryIcon();
+ }
}
notificationState = notificationManager.AreNewNotificationsAvailable();
@@ -203,6 +227,4 @@ bool WatchFaceAnalog::Refresh() {
currentDay = day;
}
}
-
- return true;
}
diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h
index 5d8c6a24..001414a6 100644
--- a/src/displayapp/screens/WatchFaceAnalog.h
+++ b/src/displayapp/screens/WatchFaceAnalog.h
@@ -32,7 +32,7 @@ namespace Pinetime {
~WatchFaceAnalog() override;
- bool Refresh() override;
+ void Refresh() override;
private:
uint8_t sHour, sMinute, sSecond;
@@ -49,6 +49,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {0};
+ DirtyValue<bool> isCharging {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
DirtyValue<bool> notificationState {false};
@@ -81,6 +82,9 @@ namespace Pinetime {
Controllers::Settings& settingsController;
void UpdateClock();
+ void SetBatteryIcon();
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp
index 2b902b3b..2ecab609 100644
--- a/src/displayapp/screens/WatchFaceDigital.cpp
+++ b/src/displayapp/screens/WatchFaceDigital.cpp
@@ -91,19 +91,31 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
lv_label_set_text(stepIcon, Symbols::shoe);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
+ Refresh();
}
WatchFaceDigital::~WatchFaceDigital() {
+ lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
-bool WatchFaceDigital::Refresh() {
+void WatchFaceDigital::Refresh() {
+ powerPresent = batteryController.IsPowerPresent();
+ if (powerPresent.IsUpdated()) {
+ lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
+ }
+
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
+ if (batteryPercent == 100) {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ } else {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ }
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
- auto isCharging = batteryController.IsCharging() or batteryController.IsPowerPresent();
- lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
}
bleState = bleController.IsConnected();
@@ -219,6 +231,4 @@ bool WatchFaceDigital::Refresh() {
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
}
-
- return running;
}
diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h
index 6a6e1ac6..e27545f3 100644
--- a/src/displayapp/screens/WatchFaceDigital.h
+++ b/src/displayapp/screens/WatchFaceDigital.h
@@ -33,7 +33,7 @@ namespace Pinetime {
Controllers::MotionController& motionController);
~WatchFaceDigital() override;
- bool Refresh() override;
+ void Refresh() override;
private:
char displayedChar[5] {};
@@ -44,6 +44,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
+ DirtyValue<bool> powerPresent {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};
@@ -72,6 +73,8 @@ namespace Pinetime {
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
+
+ lv_task_t* taskRefresh;
};
}
}
diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp
index 8190f9d7..691c40c8 100644
--- a/src/displayapp/screens/settings/QuickSettings.cpp
+++ b/src/displayapp/screens/settings/QuickSettings.cpp
@@ -88,7 +88,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
btn3_lvl = lv_label_create(btn3, nullptr);
lv_obj_set_style_local_text_font(btn3_lvl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
- if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::ON) {
+ if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::ON) {
lv_obj_add_state(btn3, LV_STATE_CHECKED);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
@@ -142,11 +142,11 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
} else if (object == btn3 && event == LV_EVENT_VALUE_CHANGED) {
if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) {
- settingsController.SetVibrationStatus(Controllers::Settings::Vibration::ON);
+ settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON);
motorController.RunForDuration(35);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
- settingsController.SetVibrationStatus(Controllers::Settings::Vibration::OFF);
+ settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
}
@@ -156,7 +156,3 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up);
}
}
-
-bool QuickSettings::Refresh() {
- return running;
-}
diff --git a/src/displayapp/screens/settings/QuickSettings.h b/src/displayapp/screens/settings/QuickSettings.h
index 2eefe1a7..c036fa5c 100644
--- a/src/displayapp/screens/settings/QuickSettings.h
+++ b/src/displayapp/screens/settings/QuickSettings.h
@@ -27,8 +27,6 @@ namespace Pinetime {
~QuickSettings() override;
- bool Refresh() override;
-
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
void UpdateScreen();
diff --git a/src/displayapp/screens/settings/SettingDisplay.cpp b/src/displayapp/screens/settings/SettingDisplay.cpp
index aaf6a9f0..d8d6c767 100644
--- a/src/displayapp/screens/settings/SettingDisplay.cpp
+++ b/src/displayapp/screens/settings/SettingDisplay.cpp
@@ -80,10 +80,6 @@ SettingDisplay::~SettingDisplay() {
settingsController.SaveSettings();
}
-bool SettingDisplay::Refresh() {
- return running;
-}
-
void SettingDisplay::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
for (int i = 0; i < optionsTotal; i++) {
diff --git a/src/displayapp/screens/settings/SettingDisplay.h b/src/displayapp/screens/settings/SettingDisplay.h
index b8ed87ec..51b23aca 100644
--- a/src/displayapp/screens/settings/SettingDisplay.h
+++ b/src/displayapp/screens/settings/SettingDisplay.h
@@ -15,7 +15,6 @@ namespace Pinetime {
SettingDisplay(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
~SettingDisplay() override;
- bool Refresh() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event);
private:
diff --git a/src/displayapp/screens/settings/SettingPineTimeStyle.cpp b/src/displayapp/screens/settings/SettingPineTimeStyle.cpp
new file mode 100644
index 00000000..c9af19b6
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingPineTimeStyle.cpp
@@ -0,0 +1,318 @@
+#include "SettingPineTimeStyle.h"
+#include <lvgl/lvgl.h>
+#include <displayapp/Colors.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ static void event_handler(lv_obj_t* obj, lv_event_t event) {
+ SettingPineTimeStyle* screen = static_cast<SettingPineTimeStyle*>(obj->user_data);
+ screen->UpdateSelected(obj, event);
+ }
+}
+
+SettingPineTimeStyle::SettingPineTimeStyle(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
+ : Screen(app), settingsController {settingsController} {
+ timebar = lv_obj_create(lv_scr_act(), nullptr);
+ 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_size(timebar, 200, 240);
+ lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0);
+
+ // Display the time
+
+ 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_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
+ lv_label_set_text(timeDD1, "12");
+ lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
+
+ 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_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
+ lv_label_set_text(timeDD2, "34");
+ lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
+
+ timeAMPM = lv_label_create(lv_scr_act(), nullptr);
+ 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_label_set_text(timeAMPM, "A\nM");
+ lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20);
+
+ // Create a 40px wide bar down the right side of the screen
+
+ sidebar = lv_obj_create(lv_scr_act(), nullptr);
+ 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_size(sidebar, 40, 240);
+ lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
+
+ // Display icons
+
+ 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_label_set_text(batteryIcon, Symbols::batteryFull);
+ lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
+
+ bleIcon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_label_set_text(bleIcon, Symbols::bluetooth);
+ lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25);
+
+ // Calendar icon
+
+ 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_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
+ lv_obj_set_size(calendarOuter, 34, 34);
+ lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
+
+ calendarInner = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
+ lv_obj_set_style_local_radius(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
+ lv_obj_set_size(calendarInner, 27, 27);
+ lv_obj_align(calendarInner, calendarOuter, LV_ALIGN_CENTER, 0, 0);
+
+ calendarBar1 = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_bg_color(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_radius(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
+ lv_obj_set_size(calendarBar1, 3, 12);
+ lv_obj_align(calendarBar1, calendarOuter, LV_ALIGN_IN_TOP_MID, -6, -3);
+
+ calendarBar2 = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_bg_color(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_radius(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
+ lv_obj_set_size(calendarBar2, 3, 12);
+ lv_obj_align(calendarBar2, calendarOuter, LV_ALIGN_IN_TOP_MID, 6, -3);
+
+ calendarCrossBar1 = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_bg_color(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_radius(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
+ lv_obj_set_size(calendarCrossBar1, 8, 3);
+ lv_obj_align(calendarCrossBar1, calendarBar1, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+
+ calendarCrossBar2 = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_bg_color(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_radius(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
+ lv_obj_set_size(calendarCrossBar2, 8, 3);
+ lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+
+ // Display date
+
+ 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_label_set_text(dateDayOfWeek, "THU");
+ lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34);
+
+ dateDay = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_label_set_text(dateDay, "25");
+ lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3);
+
+ dateMonth = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_label_set_text(dateMonth, "MAR");
+ lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32);
+
+ // Step count gauge
+ needle_colors[0] = LV_COLOR_WHITE;
+ stepGauge = lv_gauge_create(lv_scr_act(), nullptr);
+ lv_gauge_set_needle_count(stepGauge, 1, needle_colors);
+ lv_obj_set_size(stepGauge, 40, 40);
+ lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_gauge_set_scale(stepGauge, 360, 11, 0);
+ lv_gauge_set_angle_offset(stepGauge, 180);
+ lv_gauge_set_critical_value(stepGauge, (100));
+ lv_gauge_set_range(stepGauge, 0, (100));
+ lv_gauge_set_value(stepGauge, 0, 0);
+
+ lv_obj_set_style_local_pad_right(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
+ lv_obj_set_style_local_pad_left(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
+ lv_obj_set_style_local_pad_bottom(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
+ lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
+ lv_obj_set_style_local_scale_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_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, 3);
+ lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
+
+ backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_click(backgroundLabel, true);
+ lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
+ lv_obj_set_size(backgroundLabel, 240, 240);
+ lv_obj_set_pos(backgroundLabel, 0, 0);
+ lv_label_set_text(backgroundLabel, "");
+
+ btnNextTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnNextTime->user_data = this;
+ lv_obj_set_size(btnNextTime, 60, 60);
+ lv_obj_align(btnNextTime, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, -80);
+ lv_obj_set_style_local_bg_opa(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
+ lv_obj_set_event_cb(btnNextTime, event_handler);
+
+ btnPrevTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnPrevTime->user_data = this;
+ lv_obj_set_size(btnPrevTime, 60, 60);
+ lv_obj_align(btnPrevTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, -80);
+ lv_obj_set_style_local_bg_opa(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
+ lv_obj_set_event_cb(btnPrevTime, event_handler);
+
+ btnNextBar = lv_btn_create(lv_scr_act(), nullptr);
+ btnNextBar->user_data = this;
+ lv_obj_set_size(btnNextBar, 60, 60);
+ lv_obj_align(btnNextBar, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0);
+ lv_obj_set_style_local_bg_opa(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
+ lv_obj_set_event_cb(btnNextBar, event_handler);
+
+ btnPrevBar = lv_btn_create(lv_scr_act(), nullptr);
+ btnPrevBar->user_data = this;
+ lv_obj_set_size(btnPrevBar, 60, 60);
+ lv_obj_align(btnPrevBar, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0);
+ lv_obj_set_style_local_bg_opa(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
+ lv_obj_set_event_cb(btnPrevBar, event_handler);
+
+ btnNextBG = lv_btn_create(lv_scr_act(), nullptr);
+ btnNextBG->user_data = this;
+ lv_obj_set_size(btnNextBG, 60, 60);
+ lv_obj_align(btnNextBG, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 80);
+ lv_obj_set_style_local_bg_opa(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
+ lv_obj_set_event_cb(btnNextBG, event_handler);
+
+ btnPrevBG = lv_btn_create(lv_scr_act(), nullptr);
+ btnPrevBG->user_data = this;
+ lv_obj_set_size(btnPrevBG, 60, 60);
+ lv_obj_align(btnPrevBG, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 80);
+ lv_obj_set_style_local_bg_opa(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
+ lv_obj_set_event_cb(btnPrevBG, event_handler);
+
+ btnReset = lv_btn_create(lv_scr_act(), nullptr);
+ btnReset->user_data = this;
+ lv_obj_set_size(btnReset, 60, 60);
+ lv_obj_align(btnReset, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
+ lv_obj_set_style_local_bg_opa(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rst");
+ lv_obj_set_event_cb(btnReset, event_handler);
+
+ btnRandom = lv_btn_create(lv_scr_act(), nullptr);
+ btnRandom->user_data = this;
+ lv_obj_set_size(btnRandom, 60, 60);
+ lv_obj_align(btnRandom, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_bg_opa(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
+ lv_obj_set_style_local_value_str(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rnd");
+ lv_obj_set_event_cb(btnRandom, event_handler);
+}
+
+SettingPineTimeStyle::~SettingPineTimeStyle() {
+ lv_obj_clean(lv_scr_act());
+ settingsController.SaveSettings();
+}
+
+void SettingPineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event) {
+ auto valueTime = settingsController.GetPTSColorTime();
+ auto valueBar = settingsController.GetPTSColorBar();
+ auto valueBG = settingsController.GetPTSColorBG();
+
+ if (event == LV_EVENT_CLICKED) {
+ if (object == btnNextTime) {
+ valueTime = GetNext(valueTime);
+
+ settingsController.SetPTSColorTime(valueTime);
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ }
+ if (object == btnPrevTime) {
+ valueTime = GetPrevious(valueTime);
+ settingsController.SetPTSColorTime(valueTime);
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ }
+ if (object == btnNextBar) {
+ valueBar = GetNext(valueBar);
+ if(valueBar == Controllers::Settings::Colors::Black)
+ valueBar = GetNext(valueBar);
+ settingsController.SetPTSColorBar(valueBar);
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
+ }
+ if (object == btnPrevBar) {
+ valueBar = GetPrevious(valueBar);
+ if(valueBar == Controllers::Settings::Colors::Black)
+ valueBar = GetPrevious(valueBar);
+ settingsController.SetPTSColorBar(valueBar);
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
+ }
+ if (object == btnNextBG) {
+ valueBG = GetNext(valueBG);
+ settingsController.SetPTSColorBG(valueBG);
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
+ }
+ if (object == btnPrevBG) {
+ valueBG = GetPrevious(valueBG);
+ settingsController.SetPTSColorBG(valueBG);
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
+ }
+ if (object == btnReset) {
+ settingsController.SetPTSColorTime(Controllers::Settings::Colors::Teal);
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ settingsController.SetPTSColorBar(Controllers::Settings::Colors::Teal);
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ settingsController.SetPTSColorBG(Controllers::Settings::Colors::Black);
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Black));
+ }
+ if (object == btnRandom) {
+ uint8_t randTime = rand() % 17;
+ uint8_t randBar = rand() % 17;
+ uint8_t randBG = rand() % 17;
+ // Check if the time color is the same as its background, or if the sidebar is black. If so, change them to more useful values.
+ if (randTime == randBG) {
+ randBG += 1;
+ }
+ if (randBar == 3) {
+ randBar -= 1;
+ }
+ settingsController.SetPTSColorTime(static_cast<Controllers::Settings::Colors>(randTime));
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime)));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime)));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime)));
+ settingsController.SetPTSColorBar(static_cast<Controllers::Settings::Colors>(randBar));
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randBar)));
+ settingsController.SetPTSColorBG(static_cast<Controllers::Settings::Colors>(randBG));
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randBG)));
+ }
+ }
+}
+
+Pinetime::Controllers::Settings::Colors SettingPineTimeStyle::GetNext(Pinetime::Controllers::Settings::Colors color) {
+ auto colorAsInt = static_cast<uint8_t>(color);
+ Pinetime::Controllers::Settings::Colors nextColor;
+ if (colorAsInt < 16) {
+ nextColor = static_cast<Controllers::Settings::Colors>(colorAsInt + 1);
+ } else {
+ nextColor = static_cast<Controllers::Settings::Colors>(0);
+ }
+ return nextColor;
+}
+
+Pinetime::Controllers::Settings::Colors SettingPineTimeStyle::GetPrevious(Pinetime::Controllers::Settings::Colors color) {
+ auto colorAsInt = static_cast<uint8_t>(color);
+ Pinetime::Controllers::Settings::Colors prevColor;
+
+ if (colorAsInt > 0) {
+ prevColor = static_cast<Controllers::Settings::Colors>(colorAsInt - 1);
+ } else {
+ prevColor = static_cast<Controllers::Settings::Colors>(16);
+ }
+ return prevColor;
+}
diff --git a/src/displayapp/screens/settings/SettingPineTimeStyle.h b/src/displayapp/screens/settings/SettingPineTimeStyle.h
new file mode 100644
index 00000000..397bd86d
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingPineTimeStyle.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/settings/Settings.h"
+#include "displayapp/screens/Screen.h"
+
+namespace Pinetime {
+
+ namespace Applications {
+ namespace Screens {
+
+ class SettingPineTimeStyle : public Screen{
+ public:
+ SettingPineTimeStyle(DisplayApp* app, Pinetime::Controllers::Settings &settingsController);
+ ~SettingPineTimeStyle() override;
+
+ void UpdateSelected(lv_obj_t *object, lv_event_t event);
+
+ private:
+ Controllers::Settings& settingsController;
+
+ Pinetime::Controllers::Settings::Colors GetNext(Controllers::Settings::Colors color);
+ Pinetime::Controllers::Settings::Colors GetPrevious(Controllers::Settings::Colors color);
+
+ lv_obj_t * btnNextTime;
+ lv_obj_t * btnPrevTime;
+ lv_obj_t * btnNextBar;
+ lv_obj_t * btnPrevBar;
+ lv_obj_t * btnNextBG;
+ lv_obj_t * btnPrevBG;
+ lv_obj_t * btnReset;
+ lv_obj_t * btnRandom;
+ lv_obj_t * timebar;
+ lv_obj_t * sidebar;
+ lv_obj_t * timeDD1;
+ lv_obj_t * timeDD2;
+ lv_obj_t * timeAMPM;
+ lv_obj_t * dateDayOfWeek;
+ lv_obj_t * dateDay;
+ lv_obj_t * dateMonth;
+ lv_obj_t * backgroundLabel;
+ lv_obj_t * batteryIcon;
+ lv_obj_t * bleIcon;
+ lv_obj_t * calendarOuter;
+ lv_obj_t * calendarInner;
+ lv_obj_t * calendarBar1;
+ lv_obj_t * calendarBar2;
+ lv_obj_t * calendarCrossBar1;
+ lv_obj_t * calendarCrossBar2;
+ lv_obj_t * stepGauge;
+ lv_color_t needle_colors[1];
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp
new file mode 100644
index 00000000..ba3413ef
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetDate.cpp
@@ -0,0 +1,198 @@
+#include "SettingSetDate.h"
+#include <lvgl/lvgl.h>
+#include <hal/nrf_rtc.h>
+#include <nrf_log.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ constexpr int16_t POS_X_DAY = -72;
+ constexpr int16_t POS_X_MONTH = 0;
+ constexpr int16_t POS_X_YEAR = 72;
+ constexpr int16_t POS_Y_PLUS = -50;
+ constexpr int16_t POS_Y_TEXT = -6;
+ constexpr int16_t POS_Y_MINUS = 40;
+
+ void event_handler(lv_obj_t * obj, lv_event_t event) {
+ auto* screen = static_cast<SettingSetDate *>(obj->user_data);
+ screen->HandleButtonPress(obj, event);
+ }
+}
+
+SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) :
+ Screen(app),
+ dateTimeController {dateTimeController} {
+ lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_static(title, "Set current date");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15);
+
+ lv_obj_t * icon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+
+ lv_label_set_text_static(icon, Symbols::clock);
+ lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
+
+ dayValue = static_cast<int>(dateTimeController.Day());
+ lblDay = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_label_set_align(lblDay, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblDay, true);
+
+ monthValue = static_cast<int>(dateTimeController.Month());
+ lblMonth = lv_label_create(lv_scr_act(), nullptr);
+ UpdateMonthLabel();
+ lv_label_set_align(lblMonth, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblMonth, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblMonth, true);
+
+ yearValue = static_cast<int>(dateTimeController.Year());
+ if (yearValue < 2021)
+ yearValue = 2021;
+ lblYear = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_fmt(lblYear, "%d", yearValue);
+ lv_label_set_align(lblYear, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblYear, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblYear, true);
+
+ btnDayPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnDayPlus->user_data = this;
+ lv_obj_set_size(btnDayPlus, 50, 40);
+ lv_obj_align(btnDayPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_PLUS);
+ lv_obj_set_style_local_value_str(btnDayPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnDayPlus, event_handler);
+
+ btnDayMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnDayMinus->user_data = this;
+ lv_obj_set_size(btnDayMinus, 50, 40);
+ lv_obj_align(btnDayMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_MINUS);
+ lv_obj_set_style_local_value_str(btnDayMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnDayMinus, event_handler);
+
+ btnMonthPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMonthPlus->user_data = this;
+ lv_obj_set_size(btnMonthPlus, 50, 40);
+ lv_obj_align(btnMonthPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_PLUS);
+ lv_obj_set_style_local_value_str(btnMonthPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnMonthPlus, event_handler);
+
+ btnMonthMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMonthMinus->user_data = this;
+ lv_obj_set_size(btnMonthMinus, 50, 40);
+ lv_obj_align(btnMonthMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_MINUS);
+ lv_obj_set_style_local_value_str(btnMonthMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnMonthMinus, event_handler);
+
+ btnYearPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnYearPlus->user_data = this;
+ lv_obj_set_size(btnYearPlus, 50, 40);
+ lv_obj_align(btnYearPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_PLUS);
+ lv_obj_set_style_local_value_str(btnYearPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnYearPlus, event_handler);
+
+ btnYearMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnYearMinus->user_data = this;
+ lv_obj_set_size(btnYearMinus, 50, 40);
+ lv_obj_align(btnYearMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_MINUS);
+ lv_obj_set_style_local_value_str(btnYearMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnYearMinus, event_handler);
+
+ btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnSetTime->user_data = this;
+ lv_obj_set_size(btnSetTime, 120, 48);
+ lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
+ lv_obj_set_event_cb(btnSetTime, event_handler);
+}
+
+SettingSetDate::~SettingSetDate() {
+ lv_obj_clean(lv_scr_act());
+}
+
+void SettingSetDate::HandleButtonPress(lv_obj_t *object, lv_event_t event) {
+ if (event != LV_EVENT_CLICKED)
+ return;
+
+ if (object == btnDayPlus) {
+ dayValue++;
+ if (dayValue > MaximumDayOfMonth())
+ dayValue = 1;
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnDayMinus) {
+ dayValue--;
+ if (dayValue < 1)
+ dayValue = MaximumDayOfMonth();
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnMonthPlus) {
+ monthValue++;
+ if (monthValue > 12)
+ monthValue = 1;
+ UpdateMonthLabel();
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnMonthMinus) {
+ monthValue--;
+ if (monthValue < 1)
+ monthValue = 12;
+ UpdateMonthLabel();
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnYearPlus) {
+ yearValue++;
+ lv_label_set_text_fmt(lblYear, "%d", yearValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnYearMinus) {
+ yearValue--;
+ lv_label_set_text_fmt(lblYear, "%d", yearValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnSetTime) {
+ NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue);
+ dateTimeController.SetTime(static_cast<uint16_t>(yearValue),
+ static_cast<uint8_t>(monthValue),
+ static_cast<uint8_t>(dayValue),
+ 0,
+ dateTimeController.Hours(),
+ dateTimeController.Minutes(),
+ dateTimeController.Seconds(),
+ nrf_rtc_counter_get(portNRF_RTC_REG));
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
+ }
+}
+
+int SettingSetDate::MaximumDayOfMonth() const {
+ switch (monthValue) {
+ case 2:
+ if ((((yearValue % 4) == 0) && ((yearValue % 100) != 0)) || ((yearValue % 400) == 0))
+ return 29;
+ return 28;
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ return 30;
+ default:
+ return 31;
+ }
+}
+
+void SettingSetDate::CheckDay() {
+ int maxDay = MaximumDayOfMonth();
+ if (dayValue > maxDay) {
+ dayValue = maxDay;
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
+ }
+}
+
+void SettingSetDate::UpdateMonthLabel() {
+ lv_label_set_text_static(
+ lblMonth, Pinetime::Controllers::DateTime::MonthShortToStringLow(static_cast<Pinetime::Controllers::DateTime::Months>(monthValue)));
+}
diff --git a/src/displayapp/screens/settings/SettingSetDate.h b/src/displayapp/screens/settings/SettingSetDate.h
new file mode 100644
index 00000000..477337ff
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetDate.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/datetime/DateTimeController.h"
+#include "displayapp/screens/Screen.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class SettingSetDate : public Screen{
+ public:
+ SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController);
+ ~SettingSetDate() override;
+
+ void HandleButtonPress(lv_obj_t *object, lv_event_t event);
+
+ private:
+ Controllers::DateTime& dateTimeController;
+
+ int dayValue;
+ int monthValue;
+ int yearValue;
+ lv_obj_t * lblDay;
+ lv_obj_t * lblMonth;
+ lv_obj_t * lblYear;
+ lv_obj_t * btnDayPlus;
+ lv_obj_t * btnDayMinus;
+ lv_obj_t * btnMonthPlus;
+ lv_obj_t * btnMonthMinus;
+ lv_obj_t * btnYearPlus;
+ lv_obj_t * btnYearMinus;
+ lv_obj_t * btnSetTime;
+
+ int MaximumDayOfMonth() const;
+ void CheckDay();
+ void UpdateMonthLabel();
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp
new file mode 100644
index 00000000..194bf5eb
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetTime.cpp
@@ -0,0 +1,154 @@
+#include "SettingSetTime.h"
+#include <lvgl/lvgl.h>
+#include <hal/nrf_rtc.h>
+#include <nrf_log.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ constexpr int16_t POS_X_HOURS = -72;
+ constexpr int16_t POS_X_MINUTES = 0;
+ constexpr int16_t POS_X_SECONDS = 72;
+ constexpr int16_t POS_Y_PLUS = -50;
+ constexpr int16_t POS_Y_TEXT = -6;
+ constexpr int16_t POS_Y_MINUS = 40;
+ constexpr int16_t OFS_Y_COLON = -2;
+
+ void event_handler(lv_obj_t * obj, lv_event_t event) {
+ auto* screen = static_cast<SettingSetTime *>(obj->user_data);
+ screen->HandleButtonPress(obj, event);
+ }
+}
+
+SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) :
+ Screen(app),
+ dateTimeController {dateTimeController} {
+ lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_static(title, "Set current time");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15);
+
+ lv_obj_t * icon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+
+ lv_label_set_text_static(icon, Symbols::clock);
+ lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
+
+ hoursValue = static_cast<int>(dateTimeController.Hours());
+ lblHours = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblHours, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
+ lv_label_set_align(lblHours, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblHours, lv_scr_act(), LV_ALIGN_CENTER, POS_X_HOURS, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblHours, true);
+
+ lv_obj_t * lblColon1 = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblColon1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_static(lblColon1, ":");
+ lv_label_set_align(lblColon1, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblColon1, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_HOURS + POS_X_MINUTES) / 2, POS_Y_TEXT + OFS_Y_COLON);
+
+ minutesValue = static_cast<int>(dateTimeController.Minutes());
+ lblMinutes = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
+ lv_label_set_align(lblMinutes, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblMinutes, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MINUTES, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblMinutes, true);
+
+ lv_obj_t * lblColon2 = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblColon2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_static(lblColon2, ":");
+ lv_label_set_align(lblColon2, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblColon2, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_MINUTES + POS_X_SECONDS) / 2, POS_Y_TEXT + OFS_Y_COLON);
+
+ lv_obj_t * lblSeconds = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_static(lblSeconds, "00");
+ lv_label_set_align(lblSeconds, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblSeconds, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT);
+
+ btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursPlus->user_data = this;
+ lv_obj_set_size(btnHoursPlus, 50, 40);
+ lv_obj_align(btnHoursPlus, lv_scr_act(), LV_ALIGN_CENTER, -72, -50);
+ lv_obj_set_style_local_value_str(btnHoursPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnHoursPlus, event_handler);
+
+ btnHoursMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursMinus->user_data = this;
+ lv_obj_set_size(btnHoursMinus, 50, 40);
+ lv_obj_align(btnHoursMinus, lv_scr_act(), LV_ALIGN_CENTER, -72, 40);
+ lv_obj_set_style_local_value_str(btnHoursMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnHoursMinus, event_handler);
+
+ btnMinutesPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesPlus->user_data = this;
+ lv_obj_set_size(btnMinutesPlus, 50, 40);
+ lv_obj_align(btnMinutesPlus, lv_scr_act(), LV_ALIGN_CENTER, 0, -50);
+ lv_obj_set_style_local_value_str(btnMinutesPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnMinutesPlus, event_handler);
+
+ btnMinutesMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesMinus->user_data = this;
+ lv_obj_set_size(btnMinutesMinus, 50, 40);
+ lv_obj_align(btnMinutesMinus, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
+ lv_obj_set_style_local_value_str(btnMinutesMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnMinutesMinus, event_handler);
+
+ btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnSetTime->user_data = this;
+ lv_obj_set_size(btnSetTime, 120, 48);
+ lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
+ lv_obj_set_event_cb(btnSetTime, event_handler);
+}
+
+SettingSetTime::~SettingSetTime() {
+ lv_obj_clean(lv_scr_act());
+}
+
+void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) {
+ if (event != LV_EVENT_CLICKED)
+ return;
+
+ if (object == btnHoursPlus) {
+ hoursValue++;
+ if (hoursValue > 23)
+ hoursValue = 0;
+ lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnHoursMinus) {
+ hoursValue--;
+ if (hoursValue < 0)
+ hoursValue = 23;
+ lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnMinutesPlus) {
+ minutesValue++;
+ if (minutesValue > 59)
+ minutesValue = 0;
+ lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnMinutesMinus) {
+ minutesValue--;
+ if (minutesValue < 0)
+ minutesValue = 59;
+ lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnSetTime) {
+ NRF_LOG_INFO("Setting time (manually) to %02d:%02d:00", hoursValue, minutesValue);
+ dateTimeController.SetTime(dateTimeController.Year(),
+ static_cast<uint8_t>(dateTimeController.Month()),
+ dateTimeController.Day(),
+ static_cast<uint8_t>(dateTimeController.DayOfWeek()),
+ static_cast<uint8_t>(hoursValue),
+ static_cast<uint8_t>(minutesValue),
+ 0,
+ nrf_rtc_counter_get(portNRF_RTC_REG));
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h
new file mode 100644
index 00000000..8ba41eae
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetTime.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/datetime/DateTimeController.h"
+#include "displayapp/screens/Screen.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class SettingSetTime : public Screen{
+ public:
+ SettingSetTime(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController);
+ ~SettingSetTime() override;
+
+ void HandleButtonPress(lv_obj_t *object, lv_event_t event);
+
+ private:
+ Controllers::DateTime& dateTimeController;
+
+ int hoursValue;
+ int minutesValue;
+ lv_obj_t * lblHours;
+ lv_obj_t * lblMinutes;
+ lv_obj_t * btnHoursPlus;
+ lv_obj_t * btnHoursMinus;
+ lv_obj_t * btnMinutesPlus;
+ lv_obj_t * btnMinutesMinus;
+ lv_obj_t * btnSetTime;
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingSteps.cpp b/src/displayapp/screens/settings/SettingSteps.cpp
index faa843e6..bec7972b 100644
--- a/src/displayapp/screens/settings/SettingSteps.cpp
+++ b/src/displayapp/screens/settings/SettingSteps.cpp
@@ -70,11 +70,6 @@ SettingSteps::~SettingSteps() {
settingsController.SaveSettings();
}
-bool SettingSteps::Refresh() {
- return running;
-}
-
-
void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) {
uint32_t value = settingsController.GetStepsGoal();
if(object == btnPlus && (event == LV_EVENT_PRESSED)) {
@@ -95,4 +90,4 @@ void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) {
}
}
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/settings/SettingSteps.h b/src/displayapp/screens/settings/SettingSteps.h
index 0a4c2056..5fc05dee 100644
--- a/src/displayapp/screens/settings/SettingSteps.h
+++ b/src/displayapp/screens/settings/SettingSteps.h
@@ -10,22 +10,19 @@ namespace Pinetime {
namespace Applications {
namespace Screens {
- class SettingSteps : public Screen{
- public:
- SettingSteps(DisplayApp* app, Pinetime::Controllers::Settings &settingsController);
- ~SettingSteps() override;
+ class SettingSteps : public Screen {
+ public:
+ SettingSteps(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
+ ~SettingSteps() override;
- bool Refresh() override;
- void UpdateSelected(lv_obj_t *object, lv_event_t event);
-
- private:
+ void UpdateSelected(lv_obj_t* object, lv_event_t event);
- Controllers::Settings& settingsController;
+ private:
+ Controllers::Settings& settingsController;
- lv_obj_t * stepValue;
- lv_obj_t * btnPlus;
- lv_obj_t * btnMinus;
-
+ lv_obj_t* stepValue;
+ lv_obj_t* btnPlus;
+ lv_obj_t* btnMinus;
};
}
}
diff --git a/src/displayapp/screens/settings/SettingTimeFormat.cpp b/src/displayapp/screens/settings/SettingTimeFormat.cpp
index 031a2a72..c99e3a0e 100644
--- a/src/displayapp/screens/settings/SettingTimeFormat.cpp
+++ b/src/displayapp/screens/settings/SettingTimeFormat.cpp
@@ -64,10 +64,6 @@ SettingTimeFormat::~SettingTimeFormat() {
settingsController.SaveSettings();
}
-bool SettingTimeFormat::Refresh() {
- return running;
-}
-
void SettingTimeFormat::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_VALUE_CHANGED) {
for (int i = 0; i < optionsTotal; i++) {
@@ -86,4 +82,4 @@ void SettingTimeFormat::UpdateSelected(lv_obj_t* object, lv_event_t event) {
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/displayapp/screens/settings/SettingTimeFormat.h b/src/displayapp/screens/settings/SettingTimeFormat.h
index 9203b45b..eac4bdc9 100644
--- a/src/displayapp/screens/settings/SettingTimeFormat.h
+++ b/src/displayapp/screens/settings/SettingTimeFormat.h
@@ -15,7 +15,6 @@ namespace Pinetime {
SettingTimeFormat(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
~SettingTimeFormat() override;
- bool Refresh() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event);
private:
diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp
index cce9a60d..d999004b 100644
--- a/src/displayapp/screens/settings/SettingWakeUp.cpp
+++ b/src/displayapp/screens/settings/SettingWakeUp.cpp
@@ -72,10 +72,6 @@ SettingWakeUp::~SettingWakeUp() {
settingsController.SaveSettings();
}
-bool SettingWakeUp::Refresh() {
- return running;
-}
-
void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) {
using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode;
if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) {
diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h
index 248dd9ac..b9a31dc9 100644
--- a/src/displayapp/screens/settings/SettingWakeUp.h
+++ b/src/displayapp/screens/settings/SettingWakeUp.h
@@ -15,7 +15,6 @@ namespace Pinetime {
SettingWakeUp(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
~SettingWakeUp() override;
- bool Refresh() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event);
private:
diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp
index 02b90816..cdec704c 100644
--- a/src/displayapp/screens/settings/SettingWatchFace.cpp
+++ b/src/displayapp/screens/settings/SettingWatchFace.cpp
@@ -75,10 +75,6 @@ SettingWatchFace::~SettingWatchFace() {
settingsController.SaveSettings();
}
-bool SettingWatchFace::Refresh() {
- return running;
-}
-
void SettingWatchFace::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_VALUE_CHANGED) {
for (uint8_t i = 0; i < optionsTotal; i++) {
diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h
index 1930a228..d4a96c6d 100644
--- a/src/displayapp/screens/settings/SettingWatchFace.h
+++ b/src/displayapp/screens/settings/SettingWatchFace.h
@@ -15,7 +15,6 @@ namespace Pinetime {
SettingWatchFace(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
~SettingWatchFace() override;
- bool Refresh() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event);
private:
diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp
index 0ab21377..1daf311e 100644
--- a/src/displayapp/screens/settings/Settings.cpp
+++ b/src/displayapp/screens/settings/Settings.cpp
@@ -18,6 +18,9 @@ Settings::Settings(Pinetime::Applications::DisplayApp* app, Pinetime::Controller
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreen2();
+ },
+ [this]() -> std::unique_ptr<Screen> {
+ return CreateScreen3();
}},
Screens::ScreenListModes::UpDown} {
}
@@ -26,13 +29,6 @@ Settings::~Settings() {
lv_obj_clean(lv_scr_act());
}
-bool Settings::Refresh() {
-
- if (running)
- running = screens.Refresh();
- return running;
-}
-
bool Settings::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}
@@ -46,17 +42,29 @@ std::unique_ptr<Screen> Settings::CreateScreen1() {
{Symbols::home, "Watch face", Apps::SettingWatchFace},
}};
- return std::make_unique<Screens::List>(0, 2, app, settingsController, applications);
+ return std::make_unique<Screens::List>(0, 3, app, settingsController, applications);
}
std::unique_ptr<Screen> Settings::CreateScreen2() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::shoe, "Steps", Apps::SettingSteps},
- {Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
+ {Symbols::clock, "Set date", Apps::SettingSetDate},
+ {Symbols::clock, "Set time", Apps::SettingSetTime},
+ {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}
+ }};
+
+ return std::make_unique<Screens::List>(1, 3, app, settingsController, applications);
+}
+
+std::unique_ptr<Screen> Settings::CreateScreen3() {
+
+ std::array<Screens::List::Applications, 4> applications {{
+ {Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle},
{Symbols::check, "Firmware", Apps::FirmwareValidation},
{Symbols::list, "About", Apps::SysInfo},
+ {Symbols::none, "None", Apps::None},
}};
- return std::make_unique<Screens::List>(1, 2, app, settingsController, applications);
+ return std::make_unique<Screens::List>(2, 3, app, settingsController, applications);
}
diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h
index 711a6be6..6c54cdeb 100644
--- a/src/displayapp/screens/settings/Settings.h
+++ b/src/displayapp/screens/settings/Settings.h
@@ -14,17 +14,16 @@ namespace Pinetime {
Settings(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
~Settings() override;
- bool Refresh() override;
-
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
private:
Controllers::Settings& settingsController;
- ScreenList<2> screens;
+ ScreenList<3> screens;
std::unique_ptr<Screen> CreateScreen1();
std::unique_ptr<Screen> CreateScreen2();
+ std::unique_ptr<Screen> CreateScreen3();
};
}
}
diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp
index b8f8e45d..49d6ed0e 100644
--- a/src/drivers/Cst816s.cpp
+++ b/src/drivers/Cst816s.cpp
@@ -3,6 +3,7 @@
#include <legacy/nrf_drv_gpiote.h>
#include <nrfx_log.h>
#include <task.h>
+#include "drivers/PinMap.h"
using namespace Pinetime::Drivers;
@@ -17,13 +18,13 @@ using namespace Pinetime::Drivers;
Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} {
}
-void Cst816S::Init() {
- nrf_gpio_cfg_output(pinReset);
- nrf_gpio_pin_set(pinReset);
+bool Cst816S::Init() {
+ nrf_gpio_cfg_output(PinMap::Cst816sReset);
+ nrf_gpio_pin_set(PinMap::Cst816sReset);
vTaskDelay(50);
- nrf_gpio_pin_clear(pinReset);
+ nrf_gpio_pin_clear(PinMap::Cst816sReset);
vTaskDelay(5);
- nrf_gpio_pin_set(pinReset);
+ nrf_gpio_pin_set(PinMap::Cst816sReset);
vTaskDelay(50);
// Wake the touchpanel up
@@ -50,10 +51,27 @@ void Cst816S::Init() {
*/
static constexpr uint8_t irqCtl = 0b01110000;
twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1);
+
+ // There's mixed information about which register contains which information
+ if (twiMaster.Read(twiAddress, 0xA7, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) {
+ chipId = 0xFF;
+ return false;
+ }
+ if (twiMaster.Read(twiAddress, 0xA8, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) {
+ vendorId = 0xFF;
+ return false;
+ }
+ if (twiMaster.Read(twiAddress, 0xA9, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) {
+ fwVersion = 0xFF;
+ return false;
+ }
+
+ return chipId == 0xb4 && vendorId == 0 && fwVersion == 1;
}
Cst816S::TouchInfos Cst816S::GetTouchInfo() {
Cst816S::TouchInfos info;
+ uint8_t touchData[7];
auto ret = twiMaster.Read(twiAddress, 0, touchData, sizeof(touchData));
if (ret != TwiMaster::ErrorCodes::NoError) {
@@ -61,18 +79,17 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
return info;
}
- auto nbTouchPoints = touchData[2] & 0x0f;
+ // This can only be 0 or 1
+ uint8_t nbTouchPoints = touchData[touchPointNumIndex] & 0x0f;
- auto xHigh = touchData[touchXHighIndex] & 0x0f;
- auto xLow = touchData[touchXLowIndex];
- uint16_t x = (xHigh << 8) | xLow;
+ uint8_t xHigh = touchData[touchXHighIndex] & 0x0f;
+ uint8_t xLow = touchData[touchXLowIndex];
+ info.x = (xHigh << 8) | xLow;
- auto yHigh = touchData[touchYHighIndex] & 0x0f;
- auto yLow = touchData[touchYLowIndex];
- uint16_t y = (yHigh << 8) | yLow;
+ uint8_t yHigh = touchData[touchYHighIndex] & 0x0f;
+ uint8_t yLow = touchData[touchYLowIndex];
+ info.y = (yHigh << 8) | yLow;
- info.x = x;
- info.y = y;
info.touching = (nbTouchPoints > 0);
info.gesture = static_cast<Gestures>(touchData[gestureIndex]);
@@ -80,9 +97,9 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
}
void Cst816S::Sleep() {
- nrf_gpio_pin_clear(pinReset);
+ nrf_gpio_pin_clear(PinMap::Cst816sReset);
vTaskDelay(5);
- nrf_gpio_pin_set(pinReset);
+ nrf_gpio_pin_set(PinMap::Cst816sReset);
vTaskDelay(50);
static constexpr uint8_t sleepValue = 0x03;
twiMaster.Write(twiAddress, 0xA5, &sleepValue, 1);
diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h
index d4c17bb8..0fec8419 100644
--- a/src/drivers/Cst816s.h
+++ b/src/drivers/Cst816s.h
@@ -30,15 +30,21 @@ namespace Pinetime {
Cst816S(Cst816S&&) = delete;
Cst816S& operator=(Cst816S&&) = delete;
- void Init();
+ bool Init();
TouchInfos GetTouchInfo();
void Sleep();
void Wakeup();
+ uint8_t GetChipId() const {
+ return chipId;
+ }
+ uint8_t GetVendorId() const {
+ return vendorId;
+ }
+ uint8_t GetFwVersion() const {
+ return fwVersion;
+ }
private:
- static constexpr uint8_t pinIrq = 28;
- static constexpr uint8_t pinReset = 10;
-
// Unused/Unavailable commented out
static constexpr uint8_t gestureIndex = 1;
static constexpr uint8_t touchPointNumIndex = 2;
@@ -52,9 +58,12 @@ namespace Pinetime {
//static constexpr uint8_t touchXYIndex = 7;
//static constexpr uint8_t touchMiscIndex = 8;
- uint8_t touchData[7];
TwiMaster& twiMaster;
uint8_t twiAddress;
+
+ uint8_t chipId;
+ uint8_t vendorId;
+ uint8_t fwVersion;
};
}
diff --git a/src/drivers/PinMap.h b/src/drivers/PinMap.h
new file mode 100644
index 00000000..57964020
--- /dev/null
+++ b/src/drivers/PinMap.h
@@ -0,0 +1,38 @@
+#pragma once
+
+namespace Pinetime {
+ namespace PinMap {
+
+ #ifdef WATCH_P8
+ // COLMI P8
+ static constexpr uint8_t Charging = 19;
+ static constexpr uint8_t Cst816sReset = 13;
+ static constexpr uint8_t Button = 17;
+ #else
+ // Pinetime
+ static constexpr uint8_t Charging = 12;
+ static constexpr uint8_t Cst816sReset = 10;
+ static constexpr uint8_t Button = 13;
+ #endif
+
+ static constexpr uint8_t Cst816sIrq = 28;
+ static constexpr uint8_t PowerPresent = 19;
+
+ static constexpr uint8_t Motor = 16;
+
+ static constexpr uint8_t LcdBacklightLow = 14;
+ static constexpr uint8_t LcdBacklightMedium = 22;
+ static constexpr uint8_t LcdBacklightHigh = 23;
+
+ static constexpr uint8_t SpiSck = 2;
+ static constexpr uint8_t SpiMosi = 3;
+ static constexpr uint8_t SpiMiso = 4;
+
+ static constexpr uint8_t SpiFlashCsn = 5;
+ static constexpr uint8_t SpiLcdCsn = 25;
+ static constexpr uint8_t LcdDataCommand = 18;
+
+ static constexpr uint8_t TwiScl = 7;
+ static constexpr uint8_t TwiSda = 6;
+ }
+}
diff --git a/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h b/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h
index 37b81a88..5e2d636f 100644
--- a/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h
+++ b/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h
@@ -51,7 +51,7 @@ static inline void ble_ll_rfmgmt_reset(void) { }
static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { }
static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { }
static inline void ble_ll_rfmgmt_release(void) { }
-static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; }
+static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return os_cputime_get32(); }
static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; }
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 79e2ad86..fc772355 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -43,7 +43,9 @@
#include "drivers/St7789.h"
#include "drivers/TwiMaster.h"
#include "drivers/Cst816s.h"
+#include "drivers/PinMap.h"
#include "systemtask/SystemTask.h"
+#include "drivers/PinMap.h"
#include "touchhandler/TouchHandler.h"
#if NRF_LOG_ENABLED
@@ -54,14 +56,6 @@ Pinetime::Logging::NrfLogger logger;
Pinetime::Logging::DummyLogger logger;
#endif
-static constexpr uint8_t pinSpiSck = 2;
-static constexpr uint8_t pinSpiMosi = 3;
-static constexpr uint8_t pinSpiMiso = 4;
-static constexpr uint8_t pinSpiFlashCsn = 5;
-static constexpr uint8_t pinLcdCsn = 25;
-static constexpr uint8_t pinLcdDataCommand = 18;
-static constexpr uint8_t pinTwiScl = 7;
-static constexpr uint8_t pinTwiSda = 6;
static constexpr uint8_t touchPanelTwiAddress = 0x15;
static constexpr uint8_t motionSensorTwiAddress = 0x18;
static constexpr uint8_t heartRateSensorTwiAddress = 0x44;
@@ -70,33 +64,30 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0,
{Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
Pinetime::Drivers::SpiMaster::Modes::Mode3,
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
- pinSpiSck,
- pinSpiMosi,
- pinSpiMiso}};
+ Pinetime::PinMap::SpiSck,
+ Pinetime::PinMap::SpiMosi,
+ Pinetime::PinMap::SpiMiso}};
-Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
-Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
+Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
+Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
-Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn};
+Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
// The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from
// respecting correct timings. According to erratas heet, this magic value makes it run
// at ~390Khz with correct timings.
static constexpr uint32_t MaxTwiFrequencyWithoutHardwareBug {0x06200000};
-Pinetime::Drivers::TwiMaster twiMaster {NRF_TWIM1, MaxTwiFrequencyWithoutHardwareBug, pinTwiSda, pinTwiScl};
+Pinetime::Drivers::TwiMaster twiMaster {NRF_TWIM1, MaxTwiFrequencyWithoutHardwareBug, Pinetime::PinMap::TwiSda, Pinetime::PinMap::TwiScl};
Pinetime::Drivers::Cst816S touchPanel {twiMaster, touchPanelTwiAddress};
#ifdef PINETIME_IS_RECOVERY
-static constexpr bool isFactory = true;
#include "displayapp/DummyLittleVgl.h"
#include "displayapp/DisplayAppRecovery.h"
-Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
#else
-static constexpr bool isFactory = false;
#include "displayapp/LittleVgl.h"
#include "displayapp/DisplayApp.h"
-Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
#endif
+Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
Pinetime::Drivers::Bma421 motionSensor {twiMaster, motionSensorTwiAddress};
Pinetime::Drivers::Hrs3300 heartRateSensor {twiMaster, heartRateSensorTwiAddress};
@@ -105,10 +96,8 @@ TimerHandle_t debounceTimer;
TimerHandle_t debounceChargeTimer;
Pinetime::Controllers::Battery batteryController;
Pinetime::Controllers::Ble bleController;
-void ble_manager_set_ble_connection_callback(void (*connection)());
-void ble_manager_set_ble_disconnection_callback(void (*disconnection)());
-static constexpr uint8_t pinTouchIrq = 28;
-static constexpr uint8_t pinPowerPresentIrq = 19;
+static constexpr uint8_t pinTouchIrq = Pinetime::PinMap::Cst816sIrq;
+static constexpr uint8_t pinPowerPresentIrq = Pinetime::PinMap::PowerPresent;
Pinetime::Controllers::HeartRateController heartRateController;
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
@@ -119,12 +108,12 @@ Pinetime::Drivers::WatchdogView watchdogView(watchdog);
Pinetime::Controllers::NotificationManager notificationManager;
Pinetime::Controllers::MotionController motionController;
Pinetime::Controllers::TimerController timerController;
+Pinetime::Controllers::AlarmController alarmController {dateTimeController};
Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
Pinetime::Controllers::FS fs {spiNorFlash};
Pinetime::Controllers::Settings settingsController {fs};
-Pinetime::Controllers::MotorController motorController {settingsController};
-
+Pinetime::Controllers::MotorController motorController {};
Pinetime::Applications::DisplayApp displayApp(lcd,
lvgl,
@@ -139,6 +128,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd,
motorController,
motionController,
timerController,
+ alarmController,
touchHandler);
Pinetime::System::SystemTask systemTask(spi,
@@ -151,6 +141,7 @@ Pinetime::System::SystemTask systemTask(spi,
bleController,
dateTimeController,
timerController,
+ alarmController,
watchdog,
notificationManager,
motorController,
@@ -164,15 +155,25 @@ Pinetime::System::SystemTask systemTask(spi,
fs,
touchHandler);
+/* Variable Declarations for variables in noinit SRAM
+ Increment NoInit_MagicValue upon adding variables to this area
+*/
+extern uint32_t __start_noinit_data;
+extern uint32_t __stop_noinit_data;
+static constexpr uint32_t NoInit_MagicValue = 0xDEAD0000;
+uint32_t NoInit_MagicWord __attribute__((section(".noinit")));
+std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime __attribute__((section(".noinit")));
+
+
void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
- if (pin == pinTouchIrq) {
+ if (pin == Pinetime::PinMap::Cst816sIrq) {
systemTask.OnTouchEvent();
return;
}
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- if (pin == pinPowerPresentIrq and action == NRF_GPIOTE_POLARITY_TOGGLE) {
+ if (pin == Pinetime::PinMap::PowerPresent and action == NRF_GPIOTE_POLARITY_TOGGLE) {
xTimerStartFromISR(debounceChargeTimer, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
return;
@@ -305,18 +306,18 @@ int main(void) {
nrf_drv_clock_init();
// Unblock i2c?
- nrf_gpio_cfg(pinTwiScl,
+ nrf_gpio_cfg(Pinetime::PinMap::TwiScl,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0D1,
NRF_GPIO_PIN_NOSENSE);
- nrf_gpio_pin_set(pinTwiScl);
+ nrf_gpio_pin_set(Pinetime::PinMap::TwiScl);
for (uint8_t i = 0; i < 16; i++) {
- nrf_gpio_pin_toggle(pinTwiScl);
+ nrf_gpio_pin_toggle(Pinetime::PinMap::TwiScl);
nrf_delay_us(5);
}
- nrf_gpio_cfg_default(pinTwiScl);
+ nrf_gpio_cfg_default(Pinetime::PinMap::TwiScl);
debounceTimer = xTimerCreate("debounceTimer", 200, pdFALSE, (void*) 0, DebounceTimerCallback);
debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, (void*) 0, DebounceTimerChargeCallback);
@@ -324,6 +325,15 @@ int main(void) {
// retrieve version stored by bootloader
Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]);
+
+ if (NoInit_MagicWord == NoInit_MagicValue) {
+ dateTimeController.SetCurrentTime(NoInit_BackUpTime);
+ } else {
+ //Clear Memory to known state
+ memset(&__start_noinit_data,0,(uintptr_t)&__stop_noinit_data-(uintptr_t)&__start_noinit_data);
+ NoInit_MagicWord = NoInit_MagicValue;
+ }
+
lvgl.Init();
systemTask.Start();
diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp
index 9818179d..acec14c8 100644
--- a/src/recoveryLoader.cpp
+++ b/src/recoveryLoader.cpp
@@ -15,6 +15,7 @@
#include <components/brightness/BrightnessController.h>
#include <algorithm>
#include "recoveryImage.h"
+#include "drivers/PinMap.h"
#include "displayapp/icons/infinitime/infinitime-nb.c"
#include "components/rle/RleDecoder.h"
@@ -27,12 +28,6 @@ Pinetime::Logging::NrfLogger logger;
Pinetime::Logging::DummyLogger logger;
#endif
-static constexpr uint8_t pinSpiSck = 2;
-static constexpr uint8_t pinSpiMosi = 3;
-static constexpr uint8_t pinSpiMiso = 4;
-static constexpr uint8_t pinSpiFlashCsn = 5;
-static constexpr uint8_t pinLcdCsn = 25;
-static constexpr uint8_t pinLcdDataCommand = 18;
static constexpr uint8_t displayWidth = 240;
static constexpr uint8_t displayHeight = 240;
@@ -45,14 +40,14 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0,
{Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
Pinetime::Drivers::SpiMaster::Modes::Mode3,
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
- pinSpiSck,
- pinSpiMosi,
- pinSpiMiso}};
-Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn};
+ Pinetime::PinMap::SpiSck,
+ Pinetime::PinMap::SpiMosi,
+ Pinetime::PinMap::SpiMiso}};
+Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
-Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
-Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
+Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
+Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
Pinetime::Components::Gfx gfx {lcd};
Pinetime::Controllers::BrightnessController brightnessController;
diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h
index 3a195e2d..5aa218d2 100644
--- a/src/systemtask/Messages.h
+++ b/src/systemtask/Messages.h
@@ -20,7 +20,11 @@ namespace Pinetime {
EnableSleeping,
DisableSleeping,
OnNewDay,
- OnChargingEvent
+ OnChargingEvent,
+ SetOffAlarm,
+ StopRinging,
+ MeasureBatteryTimerExpired,
+ BatteryPercentageUpdated,
};
}
}
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 03bf6706..f79fd8e5 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -21,7 +21,10 @@
#include "drivers/SpiNorFlash.h"
#include "drivers/TwiMaster.h"
#include "drivers/Hrs3300.h"
+#include "drivers/PinMap.h"
#include "main.h"
+#include "BootErrors.h"
+
#include <memory>
@@ -47,6 +50,11 @@ void IdleTimerCallback(TimerHandle_t xTimer) {
sysTask->OnIdle();
}
+void MeasureBatteryTimerCallback(TimerHandle_t xTimer) {
+ auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer));
+ sysTask->PushMessage(Pinetime::System::Messages::MeasureBatteryTimerExpired);
+}
+
SystemTask::SystemTask(Drivers::SpiMaster& spi,
Drivers::St7789& lcd,
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
@@ -57,6 +65,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Controllers::TimerController& timerController,
+ Controllers::AlarmController& alarmController,
Drivers::Watchdog& watchdog,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::MotorController& motorController,
@@ -79,6 +88,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
bleController {bleController},
dateTimeController {dateTimeController},
timerController {timerController},
+ alarmController {alarmController},
watchdog {watchdog},
notificationManager {notificationManager},
motorController {motorController},
@@ -107,6 +117,8 @@ void SystemTask::Process(void* instance) {
}
void SystemTask::Work() {
+ BootErrors bootError = BootErrors::None;
+
watchdog.Setup(7);
watchdog.Start();
NRF_LOG_INFO("Last reset reason : %s", Pinetime::Drivers::Watchdog::ResetReasonToString(watchdog.ResetReason()));
@@ -121,17 +133,19 @@ void SystemTask::Work() {
fs.Init();
nimbleController.Init();
- nimbleController.StartAdvertising();
lcd.Init();
twiMaster.Init();
- touchPanel.Init();
+ if (!touchPanel.Init()) {
+ bootError = BootErrors::TouchController;
+ }
dateTimeController.Register(this);
- batteryController.Init();
+ batteryController.Register(this);
motorController.Init();
motionSensor.SoftReset();
timerController.Register(this);
timerController.Init();
+ alarmController.Init(this);
// Reset the TWI device because the motion sensor chip most probably crashed it...
twiMaster.Sleep();
@@ -142,28 +156,28 @@ void SystemTask::Work() {
settingsController.Init();
displayApp.Register(this);
- displayApp.Start();
-
- displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel);
+ displayApp.Start(bootError);
heartRateSensor.Init();
heartRateSensor.Disable();
heartRateApp.Start();
- nrf_gpio_cfg_sense_input(pinButton, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_High);
+ // Button
nrf_gpio_cfg_output(15);
nrf_gpio_pin_set(15);
nrfx_gpiote_in_config_t pinConfig;
- pinConfig.skip_gpio_setup = true;
+ pinConfig.skip_gpio_setup = false;
pinConfig.hi_accuracy = false;
pinConfig.is_watcher = false;
- pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO;
+ pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_TOGGLE;
pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown;
- nrfx_gpiote_in_init(pinButton, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_init(PinMap::Button, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_event_enable(PinMap::Button, true);
- nrf_gpio_cfg_sense_input(pinTouchIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low);
+ // Touchscreen
+ nrf_gpio_cfg_sense_input(PinMap::Cst816sIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low);
pinConfig.skip_gpio_setup = true;
pinConfig.hi_accuracy = false;
@@ -171,24 +185,24 @@ void SystemTask::Work() {
pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO;
pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup;
- nrfx_gpiote_in_init(pinTouchIrq, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_init(PinMap::Cst816sIrq, &pinConfig, nrfx_gpiote_evt_handler);
+ // Power present
pinConfig.sense = NRF_GPIOTE_POLARITY_TOGGLE;
pinConfig.pull = NRF_GPIO_PIN_NOPULL;
pinConfig.is_watcher = false;
pinConfig.hi_accuracy = false;
- pinConfig.skip_gpio_setup = true;
- nrfx_gpiote_in_init(pinPowerPresentIrq, &pinConfig, nrfx_gpiote_evt_handler);
+ pinConfig.skip_gpio_setup = false;
+ nrfx_gpiote_in_init(PinMap::PowerPresent, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_event_enable(PinMap::PowerPresent, true);
- if (nrf_gpio_pin_read(pinPowerPresentIrq)) {
- nrf_gpio_cfg_sense_input(pinPowerPresentIrq, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
- } else {
- nrf_gpio_cfg_sense_input(pinPowerPresentIrq, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
- }
+ batteryController.MeasureVoltage();
idleTimer = xTimerCreate("idleTimer", pdMS_TO_TICKS(2000), pdFALSE, this, IdleTimerCallback);
dimTimer = xTimerCreate("dimTimer", pdMS_TO_TICKS(settingsController.GetScreenTimeOut() - 2000), pdFALSE, this, DimTimerCallback);
+ measureBatteryTimer = xTimerCreate("measureBattery", batteryMeasurementPeriod, pdTRUE, this, MeasureBatteryTimerCallback);
xTimerStart(dimTimer, 0);
+ xTimerStart(measureBatteryTimer, portMAX_DELAY);
// Suppress endless loop diagnostic
#pragma clang diagnostic push
@@ -198,11 +212,6 @@ void SystemTask::Work() {
uint8_t msg;
if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) {
-
- batteryController.Update();
- // the battery does not emit events when changing charge levels, so we piggyback
- // on any system event to read and update the current values
-
Messages message = static_cast<Messages>(msg);
switch (message) {
case Messages::EnableSleeping:
@@ -226,26 +235,29 @@ void SystemTask::Work() {
touchPanel.Wakeup();
}
- nimbleController.StartAdvertising();
xTimerStart(dimTimer, 0);
spiNorFlash.Wakeup();
lcd.Wakeup();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning);
- displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel);
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp);
+ if (!bleController.IsConnected())
+ nimbleController.RestartFastAdv();
+
isSleeping = false;
isWakingUp = false;
isDimmed = false;
break;
case Messages::TouchWakeUp: {
- auto touchInfo = touchPanel.GetTouchInfo();
- if (touchInfo.touching and ((touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and
- settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or
- (touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and
- settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) {
- GoToRunning();
+ if(touchHandler.GetNewTouchInfo()) {
+ auto gesture = touchHandler.GestureGet();
+ if (gesture != Pinetime::Drivers::Cst816S::Gestures::None and ((gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and
+ settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or
+ (gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and
+ settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) {
+ GoToRunning();
+ }
}
} break;
case Messages::GoToSleep:
@@ -261,10 +273,12 @@ void SystemTask::Work() {
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime);
break;
case Messages::OnNewNotification:
- if (isSleeping && !isWakingUp) {
- GoToRunning();
+ if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) {
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ }
+ displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
}
- displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
break;
case Messages::OnTimerDone:
if (isSleeping && !isWakingUp) {
@@ -273,6 +287,16 @@ void SystemTask::Work() {
motorController.RunForDuration(35);
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TimerDone);
break;
+ case Messages::SetOffAlarm:
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ }
+ motorController.StartRinging();
+ displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered);
+ break;
+ case Messages::StopRinging:
+ motorController.StopRinging();
+ break;
case Messages::BleConnected:
ReloadIdleTimer();
isBleDiscoveryTimerRunning = true;
@@ -325,8 +349,18 @@ void SystemTask::Work() {
stepCounterMustBeReset = true;
break;
case Messages::OnChargingEvent:
+ batteryController.ReadPowerState();
motorController.RunForDuration(15);
- // Battery level is updated on every message - there's no need to do anything
+ ReloadIdleTimer();
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ }
+ break;
+ case Messages::MeasureBatteryTimerExpired:
+ batteryController.MeasureVoltage();
+ break;
+ case Messages::BatteryPercentageUpdated:
+ nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
break;
default:
@@ -338,22 +372,18 @@ void SystemTask::Work() {
if (bleDiscoveryTimer == 0) {
isBleDiscoveryTimerRunning = false;
// Services discovery is deffered from 3 seconds to avoid the conflicts between the host communicating with the
- // tharget and vice-versa. I'm not sure if this is the right way to handle this...
+ // target and vice-versa. I'm not sure if this is the right way to handle this...
nimbleController.StartDiscovery();
} else {
bleDiscoveryTimer--;
}
}
- if (xTaskGetTickCount() - batteryNotificationTick > batteryNotificationPeriod) {
- nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
- batteryNotificationTick = xTaskGetTickCount();
- }
-
monitor.Process();
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
dateTimeController.UpdateTime(systick_counter);
- if (!nrf_gpio_pin_read(pinButton))
+ NoInit_BackUpTime = dateTimeController.CurrentDateTime();
+ if (!nrf_gpio_pin_read(PinMap::Button))
watchdog.Kick();
}
// Clear diagnostic suppression
diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h
index 0266ba8a..879c1be8 100644
--- a/src/systemtask/SystemTask.h
+++ b/src/systemtask/SystemTask.h
@@ -8,6 +8,7 @@
#include <heartratetask/HeartRateTask.h>
#include <components/settings/Settings.h>
#include <drivers/Bma421.h>
+#include <drivers/PinMap.h>
#include <components/motion/MotionController.h>
#include "SystemMonitor.h"
@@ -16,6 +17,7 @@
#include "components/ble/NotificationManager.h"
#include "components/motor/MotorController.h"
#include "components/timer/TimerController.h"
+#include "components/alarm/AlarmController.h"
#include "components/fs/FS.h"
#include "touchhandler/TouchHandler.h"
@@ -31,6 +33,7 @@
#include "drivers/Watchdog.h"
#include "Messages.h"
+extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime;
namespace Pinetime {
namespace Drivers {
class Cst816S;
@@ -56,6 +59,7 @@ namespace Pinetime {
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Controllers::TimerController& timerController,
+ Controllers::AlarmController& alarmController,
Drivers::Watchdog& watchdog,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::MotorController& motorController,
@@ -100,6 +104,7 @@ namespace Pinetime {
Pinetime::Controllers::Ble& bleController;
Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Controllers::TimerController& timerController;
+ Pinetime::Controllers::AlarmController& alarmController;
QueueHandle_t systemTasksMsgQueue;
std::atomic<bool> isSleeping {false};
std::atomic<bool> isGoingToSleep {false};
@@ -120,15 +125,6 @@ namespace Pinetime {
Pinetime::Controllers::TouchHandler& touchHandler;
Pinetime::Controllers::NimbleController nimbleController;
- static constexpr uint8_t pinSpiSck = 2;
- static constexpr uint8_t pinSpiMosi = 3;
- static constexpr uint8_t pinSpiMiso = 4;
- static constexpr uint8_t pinSpiCsn = 25;
- static constexpr uint8_t pinLcdDataCommand = 18;
- static constexpr uint8_t pinButton = 13;
- static constexpr uint8_t pinTouchIrq = 28;
- static constexpr uint8_t pinPowerPresentIrq = 19;
-
static void Process(void* instance);
void Work();
void ReloadIdleTimer();
@@ -136,13 +132,13 @@ namespace Pinetime {
uint8_t bleDiscoveryTimer = 0;
TimerHandle_t dimTimer;
TimerHandle_t idleTimer;
+ TimerHandle_t measureBatteryTimer;
bool doNotGoToSleep = false;
void GoToRunning();
void UpdateMotion();
bool stepCounterMustBeReset = false;
- static constexpr TickType_t batteryNotificationPeriod = 1000 * 60 * 10; // 1 tick ~= 1ms. 1ms * 60 * 10 = 10 minutes
- TickType_t batteryNotificationTick = 0;
+ static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000);
#if configUSE_TRACE_FACILITY == 1
SystemMonitor<FreeRtosMonitor> monitor;