Author: mashuptwice <info@mashup-tech.de>
Merge remote-tracking branch 'upstream/develop' into workflow-ignore-md
.devcontainer/README.md | 25 .github/workflows/lv_sim.yml | 2 .github/workflows/main.yml | 2 README.md | 77 +- bootloader/README.md | 51 +- bootloader/ota-dfu-python/README.md | 47 +- doc/BLEFS.md | 13 doc/MemoryAnalysis.md | 91 ++- doc/MotionService.md | 12 doc/NavigationService.md | 191 ++++---- doc/PinetimeStubWithNrf52DK.md | 44 + doc/SPI-LCD-driver.md | 14 doc/SWD.md | 5 doc/ble.md | 28 doc/branches.md | 8 doc/buildAndProgram.md | 82 ++- doc/buildWithDocker.md | 32 doc/buildWithVScode.md | 25 doc/code/Apps.md | 9 doc/code/Intro.md | 6 doc/coding-convention.md | 62 +- doc/contribute.md | 68 -- doc/filesInReleaseNotes.md | 46 + doc/gdb.md | 2 doc/gettingStarted/about-software.md | 10 doc/gettingStarted/gettingStarted-1.0.md | 32 doc/gettingStarted/ota-nrfconnect.md | 1 doc/gettingStarted/updating-software.md | 12 doc/jlink.md | 10 doc/openOCD.md | 23 doc/ui_guidelines.md | 4 doc/versioning.md | 7 docker/README.md | 2 src/CMakeLists.txt | 5 src/components/settings/Settings.h | 4 src/displayapp/LittleVgl.cpp | 2 src/displayapp/fonts/README.md | 32 src/displayapp/fonts/fonts.json | 4 | 43 - | 20 src/displayapp/screens/Alarm.cpp | 3 src/displayapp/screens/BatteryInfo.cpp | 9 src/displayapp/screens/FirmwareValidation.cpp | 5 src/displayapp/screens/FlashLight.cpp | 3 src/displayapp/screens/HeartRate.cpp | 14 src/displayapp/screens/InfiniPaint.cpp | 3 src/displayapp/screens/Metronome.cpp | 3 src/displayapp/screens/Motion.cpp | 3 src/displayapp/screens/Navigation.cpp | 3 src/displayapp/screens/Notifications.cpp | 9 src/displayapp/screens/PassKey.cpp | 2 src/displayapp/screens/Steps.cpp | 4 src/displayapp/screens/StopWatch.cpp | 13 src/displayapp/screens/Styles.cpp | 3 src/displayapp/screens/Symbols.h | 1 src/displayapp/screens/SystemInfo.cpp | 3 src/displayapp/screens/Tile.cpp | 3 src/displayapp/screens/Timer.cpp | 3 src/displayapp/screens/WatchFaceAnalog.cpp | 5 src/displayapp/screens/WatchFaceDigital.cpp | 2 src/displayapp/screens/WatchFacePineTimeStyle.cpp | 4 src/displayapp/screens/settings/QuickSettings.cpp | 60 +- src/displayapp/screens/settings/QuickSettings.h | 2 src/displayapp/screens/settings/SettingSetTime.cpp | 4 src/displayapp/screens/settings/SettingShakeThreshold.cpp | 4 src/displayapp/screens/settings/SettingSteps.cpp | 1 src/displayapp/screens/settings/SettingWatchFace.cpp | 1 src/displayapp/widgets/Counter.cpp | 27 src/displayapp/widgets/Counter.h | 1 src/displayapp/widgets/PageIndicator.cpp | 5 src/displayapp/widgets/StatusIcons.cpp | 2 src/drivers/St7789.cpp | 14 src/libs/lv_conf.h | 2 src/systemtask/SystemTask.cpp | 25
diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 1932a9d4f084f6186d3ba8cf94514b91d43dd45f..b243a64a77c4302ae0cae90a4781ba7b0ca5c7cb 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -1,7 +1,6 @@ # VS Code Dev Container -This is a docker-based interactive development environment using VS Code and Docker Dev Containers removing the need to install any tools locally* - +This is a docker-based interactive development environment using VS Code and Docker Dev Containers removing the need to install any tools locally\* ## Requirements @@ -16,34 +15,30 @@ ### Code editing, and building. 1. Clone InfiniTime and update submodules 2. Launch VS Code -3. Open InfiniTime directory, -4. Allow VS Code to open folder with devcontainer. +3. Open InfiniTime directory, +4. Allow VS Code to open folder with devcontainer. -After this the environment will be built if you do not currently have a container setup, it will install all the necessary tools and extra VSCode extensions. +After this the environment will be built if you do not currently have a container setup, it will install all the necessary tools and extra VSCode extensions. In order to build InfiniTime we need to run the initial submodule init and CMake commands. -#### Manually +#### Manually - You can use the VS Code terminal to run the CMake commands as outlined in the [build instructions](blob/develop/doc/buildAndProgram.md) +You can use the VS Code terminal to run the CMake commands as outlined in the [build instructions](blob/develop/doc/buildAndProgram.md) #### Script The dev environment comes with some scripts to make this easier, They are located in /opt/. -There are also VS Code tasks provided should you desire to use those. +There are also VS Code tasks provided should you desire to use those. The task "update submodules" will update the git submodules - - ### Build You can use the build.sh script located in /opt/ CMake is also configured and controls for the CMake plugin are available in VS Code - - ### Debugging @@ -51,10 +46,10 @@ Docker on windows does not support passing USB devices to the underlying WSL2 subsystem, To get around this we use OpenOCD in server mode running on the host. `openocd -f <yourinterface> -f <nrf52.cfg target file>` -This will launch OpenOCD in server mode and attach it to the MCU. +This will launch OpenOCD in server mode and attach it to the MCU. The default launch.json file expects OpenOCD to be listening on port 3333, edit if needed - ## Current Issues -Currently WSL2 Has some real performance issues with IO on a windows host. Accessing files on the virtualized filesystem is much faster. Using VS Codes "clone in container" feature of the Remote - Containers will get around this. After the container is built you will need to update the submodules and follow the build instructions like normal \ No newline at end of file + +Currently WSL2 Has some real performance issues with IO on a windows host. Accessing files on the virtualized filesystem is much faster. Using VS Codes "clone in container" feature of the Remote - Containers will get around this. After the container is built you will need to update the submodules and follow the build instructions like normal diff --git a/.github/workflows/lv_sim.yml b/.github/workflows/lv_sim.yml index 7b02fb1c47f1b2f39110462b75c159f7f53bc109..c950168cffec29626536e9418898e329ec350561 100644 --- a/.github/workflows/lv_sim.yml +++ b/.github/workflows/lv_sim.yml @@ -7,13 +7,11 @@ push: branches: [ master, develop ] paths-ignore: - 'doc/**' - - 'images/**' - '**.md' pull_request: branches: [ develop ] paths-ignore: - 'doc/**' - - 'images/**' - '**.md' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0f0686b6b558a15a9401bf34181ff70fb9410b0f..81054bcb99ddc8777fc2677581f5c1eafd3970b9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,13 +10,11 @@ push: branches: [ master, develop ] paths-ignore: - 'doc/**' - - 'images/**' - '**.md' pull_request: branches: [ develop ] paths-ignore: - 'doc/**' - - 'images/**' - '**.md' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/README.md b/README.md index 7c52cb44e23d5f54d6c9f8aa855b47f98c70bfbd..a3d2229bbeed0c3d629fe2a38c20acbe72677bf4 100644 --- a/README.md +++ b/README.md @@ -2,70 +2,71 @@ # [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime) [](https://github.com/InfiniTimeOrg/InfiniTime/actions) - + Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++. ## New to InfiniTime? - - [Getting started with InfiniTime](doc/gettingStarted/gettingStarted-1.0.md) - - [Updating the software](doc/gettingStarted/updating-software.md) - - [About the firmware and bootloader](doc/gettingStarted/about-software.md) +- [Getting started with InfiniTime](doc/gettingStarted/gettingStarted-1.0.md) +- [Updating the software](doc/gettingStarted/updating-software.md) +- [About the firmware and bootloader](doc/gettingStarted/about-software.md) ### Companion apps - - [Gadgetbridge](https://gadgetbridge.org/) (Android) - - [AmazFish](https://openrepos.net/content/piggz/amazfish/) (SailfishOS) - - [Siglo](https://github.com/alexr4535/siglo) (Linux) - - [InfiniLink](https://github.com/InfiniTimeOrg/InfiniLink) (iOS) **[Looking for a new maintainer]** - - [ITD](https://gitea.arsenm.dev/Arsen6331/itd) (Linux) +- [Gadgetbridge](https://gadgetbridge.org/) (Android) +- [AmazFish](https://openrepos.net/content/piggz/amazfish/) (SailfishOS) +- [Siglo](https://github.com/alexr4535/siglo) (Linux) +- [InfiniLink](https://github.com/InfiniTimeOrg/InfiniLink) (iOS) **[Looking for a new maintainer]** +- [ITD](https://gitea.arsenm.dev/Arsen6331/itd) (Linux) ## Development - - [InfiniTime Vision](doc/InfiniTimeVision.md) - - [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) - - [Tips on designing an app UI](doc/ui_guidelines.md) - - [Bootloader, OTA and DFU](bootloader/README.md) - - [Versioning](doc/versioning.md) - - [Project branches](doc/branches.md) - - [Files included in the release notes](doc/filesInReleaseNotes.md) +- [InfiniTime Vision](doc/InfiniTimeVision.md) +- [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) +- [Tips on designing an app UI](doc/ui_guidelines.md) +- [Bootloader, OTA and DFU](bootloader/README.md) +- [Versioning](doc/versioning.md) +- [Project branches](doc/branches.md) +- [Files included in the release notes](doc/filesInReleaseNotes.md) ### Contributing - - [How to contribute?](doc/contribute.md) - - [Coding conventions](doc/coding-convention.md) +- [How to contribute?](doc/contribute.md) +- [Coding conventions](doc/coding-convention.md) ### Build, flash and debug - - [InfiniTime simulator](https://github.com/InfiniTimeOrg/InfiniSim) - - [Build the project](doc/buildAndProgram.md) - - [Build the project with Docker](doc/buildWithDocker.md) - - [Build the project with VSCode](doc/buildWithVScode.md) - - [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md) - - [Flash the firmware using SWD interface](doc/SWD.md) - - [Flash the firmware using JLink](doc/jlink.md) - - [Flash the firmware using GDB](doc/gdb.md) - - [Stub using NRF52-DK](doc/PinetimeStubWithNrf52DK.md) +- [InfiniTime simulator](https://github.com/InfiniTimeOrg/InfiniSim) +- [Build the project](doc/buildAndProgram.md) +- [Build the project with Docker](doc/buildWithDocker.md) +- [Build the project with VSCode](doc/buildWithVScode.md) +- [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md) +- [Flash the firmware using SWD interface](doc/SWD.md) +- [Flash the firmware using JLink](doc/jlink.md) +- [Flash the firmware using GDB](doc/gdb.md) +- [Stub using NRF52-DK](doc/PinetimeStubWithNrf52DK.md) ### API - - [BLE implementation and API](doc/ble.md) +- [BLE implementation and API](doc/ble.md) ### Architecture and technical topics - - [Memory analysis](doc/MemoryAnalysis.md) +- [Memory analysis](doc/MemoryAnalysis.md) ## Licenses This project is released under the GNU General Public License version 3 or, at your option, any later version. It integrates the following projects: - - RTOS : **[FreeRTOS](https://freertos.org)** under the MIT license - - UI : **[LittleVGL/LVGL](https://lvgl.io/)** under the MIT license - - BLE stack : **[NimBLE](https://github.com/apache/mynewt-nimble)** under the Apache 2.0 license - - Font : **[Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)** under the Apache 2.0 license + +- RTOS : **[FreeRTOS](https://freertos.org)** under the MIT license +- UI : **[LittleVGL/LVGL](https://lvgl.io/)** under the MIT license +- BLE stack : **[NimBLE](https://github.com/apache/mynewt-nimble)** under the Apache 2.0 license +- Font : **[Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)** under the Apache 2.0 license ## Credits @@ -73,6 +74,6 @@ I’m not working alone on this project. First, many people create PR for this projects. Then, there is the whole #pinetime community : a lot of people all around the world who are hacking, searching, experimenting and programming the Pinetime. We exchange our ideas, experiments and code in the chat rooms and forums. Here are some people I would like to highlight: - - [Atc1441](https://github.com/atc1441/) : He works on an Arduino based firmware for the Pinetime and many other smartwatches based on similar hardware. He was of great help when I was implementing support for the BMA421 motion sensor and I²C driver. - - [Koen](https://github.com/bosmoment) : He’s working on a firmware based on RiotOS. He integrated similar libs as me : NimBLE, LittleVGL,… His help was invaluable too! - - [Lup Yuen Lee](https://github.com/lupyuen) : He is everywhere: he works on a Rust firmware, builds a MCUBoot based bootloader for the Pinetime, designs a Flutter based companion app for smartphones and writes a lot of articles about the Pinetime! +- [Atc1441](https://github.com/atc1441/) : He works on an Arduino based firmware for the Pinetime and many other smartwatches based on similar hardware. He was of great help when I was implementing support for the BMA421 motion sensor and I²C driver. +- [Koen](https://github.com/bosmoment) : He’s working on a firmware based on RiotOS. He integrated similar libs as me : NimBLE, LittleVGL,… His help was invaluable too! +- [Lup Yuen Lee](https://github.com/lupyuen) : He is everywhere: he works on a Rust firmware, builds a MCUBoot based bootloader for the Pinetime, designs a Flutter based companion app for smartphones and writes a lot of articles about the Pinetime! diff --git a/bootloader/README.md b/bootloader/README.md index 2cb6b8bf2fcef1a000b9635b4dafbd8ef98bd18d..51ddfa6bf240de80db2b384c03f336a648a5edf0 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -1,4 +1,5 @@ # About this bootloader + The [bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/tree/master/libs/pinetime_boot/src) is mostly developed by [Lup Yuen](https://github.com/lupyuen). It is based on [MCUBoot](https://www.mcuboot.com) and [Mynewt](https://mynewt.apache.org/). The goal of this project is to provide a common bootloader for multiple (all?) Pinetime projects. It allows to upgrade the current bootloader and even replace the current application by another one that supports the same bootloader. @@ -12,6 +13,7 @@ As this bootloader does not provide any OTA capability, it is not able to actually download a new version of the application. Providing OTA functionality is thus the responsibility of the application firmware. # About MCUBoot + MCUBoot is run at boot time. In normal operation, it just jumps to the reset handler of the application firmware to run it. Once the application firmware is running, MCUBoot does not run at all.  @@ -19,8 +21,9 @@ But MCUBoot does much more than that : it can upgrade the firmware that is currently running by a new one, and it is also able to revert to the previous version of the firmware in case the new one does not run properly. To do this, it uses 2 memory 'slots' : - - **The primary slot** : it contains the current firmware, the one that will be executed by MCUBoot - - **The secondary slot** : it is used to store the upgraded version of the firmware, when available. + +- **The primary slot** : it contains the current firmware, the one that will be executed by MCUBoot +- **The secondary slot** : it is used to store the upgraded version of the firmware, when available. At boot time, MCUBoot detects that a new version of the firmware is available in the secondary slot and swaps them : the current version of the firmware is copied from the primary to the secondary slot and vice-versa. @@ -35,6 +38,7 @@ Note than MCUBoot **does not** provide any means to download and store the new version of the firmware into the secondary slot. This must be implemented by the application firmware. # Degraded cases + This chapter describes degraded cases that are handled by our bootloader and those that are not supported. Case | Current bootloader | Solution @@ -50,72 +54,73 @@ # Using the bootloader ## Bootloader graphic + The bootloader loads a graphic (Pinetime logo) from the SPI Flash memory. If this graphic is not loaded in the memory, the LCD will display garbage (the content of the SPI flash memory). The SPI Flash memory is not accessible via the SWD debugger. Use the firmware 'pinetime-graphics' to load the graphic into memory. All you have to do is build it and program it at address 0x00 : - - Build: -``` -$ make pinetime-graphics +- Build: + +```sh +make pinetime-graphics ``` - - Program (using OpenOCD for example) : +- Program (using OpenOCD for example) : + ``` program pinetime-graphics.bin 0 ``` - - Let it run for ~10s (it does nothing for 5 seconds, then write the logo into the SPI memory, then (slowly) displays it on the LCD). +- Let it run for ~10s (it does nothing for 5 seconds, then write the logo into the SPI memory, then (slowly) displays it on the LCD). ## Bootloader binary + The binary comes from https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4 It must be flash at address **0x00** in the internal flash memory. Using OpenOCD: -` -program bootloader-5.0.4.bin 0 -` +`program bootloader-5.0.4.bin 0` ## Application firmware image + Build the binary compatible with the booloader: -` -make pinetime-mcuboot-app -` +`make pinetime-mcuboot-app` The binary is located in *<build directory>/src/pinetime-mcuboot-app.bin*. It must me converted into a MCUBoot image using *imgtool.py* from [MCUBoot](https://github.com/mcu-tools/mcuboot/tree/master/scripts). Simply checkout the project and run the script <mcuboot root>/scripts/imgtool.py with the following command line: -` -imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header <build directory>/src/pinetime-mcuboot-app.bin image.bin -` +```sh +imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header <build directory>/src/pinetime-mcuboot-app.bin image.bin +``` The image must be then flashed at address **0x8000** in the internal flash memory. Using OpenOCD: -` -program image.bin 0x8000 -` +`program image.bin 0x8000` ## OTA and DFU + Pack the image into a .zip file for the NRF DFU protocol: -` +```sh adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application image.bin dfu.zip -` +``` Use NRFConnect or dfu.py (in <project root>/bootloader/ota-dfu-python) to upload the zip file to the device: -` +```sh sudo dfu.py -z /home/jf/nrf52/bootloader/dfu.zip -a <pinetime MAC address> --legacy -` +``` **Note** : dfu.py is a slightly modified version of [this repo](https://github.com/daniel-thompson/ota-dfu-python). ### Firmware validation + Once the OTA is done, InfiniTime will reset the watch to apply the update. When the watch reboots, the new firmware is running. One last step is needed to finalize the upgrade : the new firmware must be manually validated. If the watch resets while the image is not validated, the bootloader will automatically revert to the previous version of the firmware. diff --git a/bootloader/ota-dfu-python/README.md b/bootloader/ota-dfu-python/README.md index 3397db4d5d05eb24590e4f87ee66bfccac05f559..c38e597a8baaa0aa73587822850cc3e83f3255b1 100644 --- a/bootloader/ota-dfu-python/README.md +++ b/bootloader/ota-dfu-python/README.md @@ -1,13 +1,13 @@ # Python nRF5 OTA DFU Controller So... this is my fork of dingara's fork of astronomer80's fork of -foldedtoad's Python OTA DFU utility. +foldedtoad's Python OTA DFU utility. -My own contribution is little more than a brute force conversion to -python3. It is sparsely tested so there are likely to be a few +My own contribution is little more than a brute force conversion to +python3. It is sparsely tested so there are likely to be a few remaining bytes versus string bugs remaining in the places I didn't test . I used it primarily as part of -[wasp-os](https://github.com/daniel-thompson/wasp-os) as a way to +[wasp-os](https://github.com/daniel-thompson/wasp-os) as a way to deliver OTA updates to nRF52-based smart watches, especially the [Pine64 PineTime](https://www.pine64.org/pinetime/). @@ -17,24 +17,24 @@ This is a Python program that uses `gatttool` (provided with the Linux BlueZ driver) to achieve Over The Air (OTA) Device Firmware Updates (DFU) to a Nordic Semiconductor nRF5 (either nRF51 or nRF52) device via Bluetooth Low Energy (BLE). ### Main features: -* Perform OTA DFU to an nRF5 peripheral without an external USB BLE dongle. -* Ability to detect if the peripheral is running in application mode or bootloader, and automatically switch if needed (buttonless). -* Support for both Legacy (SDK <= 11) and Secure (SDK >= 12) bootloader. +- Perform OTA DFU to an nRF5 peripheral without an external USB BLE dongle. +- Ability to detect if the peripheral is running in application mode or bootloader, and automatically switch if needed (buttonless). +- Support for both Legacy (SDK <= 11) and Secure (SDK >= 12) bootloader. Before using this utility the nRF5 peripheral device needs to be programmed with a DFU bootloader (see Nordic Semiconductor documentation/examples for instructions on that). ## Prerequisites -* BlueZ 5.4 or above -* Python 3.6 -* Python `pexpect` module (available via pip) -* Python `intelhex` module (available via pip) +- BlueZ 5.4 or above +- Python 3.6 +- Python `pexpect` module (available via pip) +- Python `intelhex` module (available via pip) ## Firmware Build Requirement -* Your nRF5 peripheral firmware build method will produce a firmware file ending with either `*.hex` or `*.bin`. -* Your nRF5 firmware build method will produce an Init file ending with `.dat`. -* The typical naming convention is `application.bin` and `application.dat`, but this utility will accept other names. +- Your nRF5 peripheral firmware build method will produce a firmware file ending with either `*.hex` or `*.bin`. +- Your nRF5 firmware build method will produce an Init file ending with `.dat`. +- The typical naming convention is `application.bin` and `application.dat`, but this utility will accept other names. ## Generating init files @@ -75,14 +75,13 @@ LE Scan ... CD:E3:4A:47:1C:E4 <TARGET_NAME> CD:E3:4A:47:1C:E4 (unknown) - ## Example Output ================================ == == == DFU Server == == == - ================================ + ================================ Sending file application.bin to CD:E3:4A:47:1C:E4 bin array size: 60788 @@ -105,14 +104,14 @@ DFU Server done ## TODO: -* Implement link-loss procedure for Legacy Controller. -* Update example output in readme. -* Add makefile examples. -* More code cleanup. +- Implement link-loss procedure for Legacy Controller. +- Update example output in readme. +- Add makefile examples. +- More code cleanup. ## Info & References -* [Nordic Legacy DFU Service](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/bledfu_transport_bleservice.html?cp=4_0_3_4_3_1_4_1) -* [Nordic Legacy DFU sequence diagrams](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/bledfu_transport_bleprofile.html?cp=4_0_3_4_3_1_4_0_1_6#ota_profile_pkt_rcpt_notif) -* [Nordic Secure DFU bootloader](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v12.2.0/lib_dfu_transport_ble.html?cp=4_0_1_3_5_2_2) -* [nrfutil](https://github.com/NordicSemiconductor/pc-nrfutil) +- [Nordic Legacy DFU Service](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/bledfu_transport_bleservice.html?cp=4_0_3_4_3_1_4_1) +- [Nordic Legacy DFU sequence diagrams](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/bledfu_transport_bleprofile.html?cp=4_0_3_4_3_1_4_0_1_6#ota_profile_pkt_rcpt_notif) +- [Nordic Secure DFU bootloader](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v12.2.0/lib_dfu_transport_ble.html?cp=4_0_1_3_5_2_2) +- [nrfutil](https://github.com/NordicSemiconductor/pc-nrfutil) diff --git a/doc/BLEFS.md b/doc/BLEFS.md index 519d84a90fb981aa8c258c207b636c4ee116d454..5374fd878780f740cb4af8b93d2c1ce879a6df4e 100644 --- a/doc/BLEFS.md +++ b/doc/BLEFS.md @@ -1,4 +1,5 @@ # BLE FS + --- The BLE FS protocol in InfiniTime is mostly Adafruit's BLE file transfer protocol, as described in [adafruit/Adafruit_CircuitPython_BLE_File_Transfer](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer). There are some deviations, such as the status codes. These will be described later in the document. @@ -13,7 +14,7 @@ ### Version UUID: `adaf0100-4669-6c65-5472-616e73666572` -The version characteristic returns the version of the protocol to which the sender adheres. It returns a single unsigned 32-bit integer. The latest version at the time of writing this is 4. +The version characteristic returns the version of the protocol to which the sender adheres. It returns a single unsigned 32-bit integer. The latest version at the time of writing this is 4. ### Transfer @@ -125,7 +126,7 @@ - 1 byte of padding - Unsigned 16-bit integer encoding the length of the file path. - File path: UTF-8 encoded string that is _not_ null terminated. -The response to this packet will be as follows. Responses will be sent until the final entry, which will have entry number == total entries +The response to this packet will be as follows. Responses will be sent until the final entry, which will have entry number == total entries - Command (single byte): `0x51` - Status (signed 8-bit integer) @@ -133,9 +134,9 @@ - Unsigned 16-bit integer encoding the length of the file path. - Unsigned 32-bit integer encoding the entry number - Unsigned 32-bit integer encoding the total amount of entries - Flags: unsigned 32-bit integer - + Bit 0: Set when entry is a directory - + Bits 1-7: Reserved -- Unsigned 64-bit integer encoding the unix timestamp of the modification time with nanosecond resolution + - Bit 0: Set when entry is a directory + - Bits 1-7: Reserved +- Unsigned 64-bit integer encoding the unix timestamp of the modification time with nanosecond resolution - Unsigned 32-bit integer encoding the size of the file - Path: UTF-8 encoded string that is _not_ null terminated. @@ -164,4 +165,4 @@ ### Status codes The status codes returned by InfiniTime are a signed 8-bit integer, rather than an unsigned one as described in the spec. -InfiniTime uses LittleFS error codes rather than the ones described in the spec. Those codes can be found in [lfs.h](https://github.com/littlefs-project/littlefs/blob/master/lfs.h#L70). \ No newline at end of file +InfiniTime uses LittleFS error codes rather than the ones described in the spec. Those codes can be found in [lfs.h](https://github.com/littlefs-project/littlefs/blob/master/lfs.h#L70). diff --git a/doc/MemoryAnalysis.md b/doc/MemoryAnalysis.md index 846d507966369e698f6ec52b23c86bff3b132cbc..0feb0f9ec61336058b5f8d64712a8408525fe98f 100644 --- a/doc/MemoryAnalysis.md +++ b/doc/MemoryAnalysis.md @@ -1,25 +1,28 @@ # Memory analysis + The PineTime is equipped with the following memories: - - The internal RAM : **64KB** - - The internal Flash : **512KB** - - The external (SPI) Flash : **4MB** + +- The internal RAM : **64KB** +- The internal Flash : **512KB** +- The external (SPI) Flash : **4MB** 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/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. Here is a small description of these sections and where they end up in memory: - - **TEXT** = code (FLASH) - - **RODATA** = constants (FLASH) - - **DATA** = initialized variables (FLASH + RAM) - - **BSS** = uninitialized variables (RAM) - +- **TEXT** = code (FLASH) +- **RODATA** = constants (FLASH) +- **DATA** = initialized variables (FLASH + RAM) +- **BSS** = uninitialized variables (RAM) ## Internal FLASH + The internal flash memory stores the whole firmware: code, variable that are not default-initialized, constants... The content of the flash memory can be easily analyzed thanks to the MAP file generated by the compiler. This file lists all the symbols from the program along with their size and location (section and addresses) in RAM and FLASH. @@ -41,62 +44,71 @@ Also, as Linkermapviz is written in Python, you can easily modify and adapt it to your firmware or export data in another format. For example, [here it is modified to parse the contents of the MAP file and export it in a CSV file](https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620). This file could later be opened in LibreOffice Calc where sort/filter functionality could be used 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...  Puncover is really easy to install: - - Clone the repo and cd into the cloned directory - - Setup a venv - - `python -m virtualenv venv` - - `source venv/bin/activate` - - Install : `pip install .` - - Run : `puncover --gcc_tools_base=/path/to/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi- --elf_file /path/to/build/directory/src/pinetime-app-1.1.0.out --src_root /path/to/sources --build_dir /path/to/build/directory` - - Replace - * `/path/to/gcc-arm-none-eabi-10.3-2021.10/bin` with the path to your gcc-arm-none-eabi toolchain - * `/path/to/build/directory/src/pinetime-app-1.1.0.out` with the path to the binary generated by GCC (.out file) - * `/path/to/sources` with the path to the root folder of the sources (checkout directory) - * `/path/to/build/directory` with the path to the build directory - - Launch a browser at http://localhost:5000/ +- Clone the repo and cd into the cloned directory +- Setup a venv + - `python -m virtualenv venv` + - `source venv/bin/activate` +- Install : `pip install .` +- Run : `puncover --gcc_tools_base=/path/to/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi- --elf_file /path/to/build/directory/src/pinetime-app-1.1.0.out --src_root /path/to/sources --build_dir /path/to/build/directory` + - Replace + - `/path/to/gcc-arm-none-eabi-10.3-2021.10/bin` with the path to your gcc-arm-none-eabi toolchain + - `/path/to/build/directory/src/pinetime-app-1.1.0.out` with the path to the binary generated by GCC (.out file) + - `/path/to/sources` with the path to the root folder of the sources (checkout directory) + - `/path/to/build/directory` with the path to the build directory +- Launch a browser at http://localhost:5000/ ### Analysis + Using the MAP file and tools, we can easily see what symbols are using most of the flash memory. In this case, unsurprisingly, fonts and graphics are the largest use of flash memory.  This way, you can easily check what needs to be optimized. We should find a way to store big static data (like fonts and graphics) in the external flash memory, for example. -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. +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/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620 - - Analysis with Puncover : https://github.com/InfiniTimeOrg/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... ### Data + RAM memory can be *statically* allocated, meaning that the size and position of the data are known at compile-time: You can easily analyze the memory used by variables declared in the global scope using the MAP. You'll find them in the .BSS or .DATA sections. Linkermapviz and Puncover can be used to analyze their memory usage. Variables declared in the scope of a function will be allocated on the stack. It means that the stack usage will vary according to the state of the program, and cannot be easily analyzed at compile time. + ``` -uint8_t buffer[1024] +uint8_t buffer[1024] int main() { - int a; + int a; } ``` #### Analysis -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. + +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/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: + Edit <NRFSDK>/modules/nrfx/mdk/gcc_startup_nrf52.S and add the following code after the copy of the data from read only memory to RAM at around line 243: ``` @@ -138,6 +150,7 @@ /* -- */ ``` #### Dump RAM memory and check usage + Dumping the content of the ram is easy using JLink debugger and `nrfjprog`: ``` @@ -193,13 +206,16 @@ 000ffe0 0000 2001 0000 0000 ef30 e000 0010 0000 000fff0 7fc0 2000 4217 0001 3f0a 0001 0000 6100 ``` -#### Analysis +#### Analysis + 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/InfiniTimeOrg/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/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: @@ -210,6 +226,7 @@ NRF_LOG_INFO("heap : %d", m.uordblks); ``` #### Analysis + According to my experimentation, InfiniTime uses ~6000bytes of heap most of the time. Except when the Navigation app is launched, where the heap usage exceeds 9500 bytes (meaning that the heap overflows and could potentially corrupt the stack). This is a bug that should be fixed in #362. To know exactly what's consuming heap memory, you can `wrap` functions like `malloc()` into your own functions. In this wrapper, you can add logging code or put breakpoints: @@ -225,6 +242,7 @@ return __real_malloc(size); } } ``` + Now, your function `__wrap_malloc()` will be called instead of `malloc()`. You can call the actual malloc from the stdlib by calling `__real_malloc()`. Using this technique, I was able to trace all malloc calls at boot (boot -> digital watchface): @@ -239,12 +257,14 @@ - digital clock = 96 + 152 - hr task = 304 #### Links - - 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/ + +- 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/ ## LVGL + I did a deep analysis of the usage of the buffer dedicated to lvgl (managed by lv_mem). This buffer is used by lvgl to allocated memory for drivers (display/touch), screens, themes, and all widgets created by the apps. @@ -262,11 +282,13 @@ Then, initializing the digital clock face costs **1541 bytes**. 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/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-850890064 +- https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-850890064 ## FreeRTOS heap and task stack + FreeRTOS statically allocate its own heap buffer in a global variable named `ucHeap`. This is an array of *uint8_t*. Its size is specified by the definition `configTOTAL_HEAP_SIZE` in *FreeRTOSConfig.h* FreeRTOS uses this buffer to allocate memory for tasks stack and all the RTOS object created during runtime (timers, mutexes...). @@ -275,7 +297,6 @@ ``` NRF_LOG_INFO("Free heap : %d", xPortGetFreeHeapSize()); ``` - The function `uxTaskGetSystemState()` fetches some information about the running tasks like its name and the minimum amount of stack space that has remained for the task since the task was created: @@ -285,5 +306,3 @@ auto nb = uxTaskGetSystemState(tasksStatus, 10, NULL); for (int i = 0; i < nb; i++) { NRF_LOG_INFO("Task [%s] - %d", tasksStatus[i].pcTaskName, tasksStatus[i].usStackHighWaterMark); ``` - - diff --git a/doc/MotionService.md b/doc/MotionService.md index 7cec3fbaacfe664bd7cde16c8deb3ba088bdff59..429794acb3e8b49aa66273dcf0ff4d5f273cbf93 100644 --- a/doc/MotionService.md +++ b/doc/MotionService.md @@ -1,17 +1,23 @@ # Motion Service + ## Introduction + The motion service exposes step count and raw X/Y/Z motion value as READ and NOTIFY characteristics. ## Service + The service UUID is **00030000-78fc-48fe-8e23-433b3a1942d0** ## Characteristics + ### Step count (UUID 00030001-78fc-48fe-8e23-433b3a1942d0) + The current number of steps represented as a single `uint32_t` (4 bytes) value. ### Raw motion values (UUID 00030002-78fc-48fe-8e23-433b3a1942d0) + The current raw motion values. This is a 3 `int16_t` array: - - [0] : X - - [1] : Y - - [2] : Z +- [0] : X +- [1] : Y +- [2] : Z diff --git a/doc/NavigationService.md b/doc/NavigationService.md index d890cb26e133c01e6552005a7b6fe92601061617..e2a82b33449d06059985cc7b1a2b5a32ccca3d84 100644 --- a/doc/NavigationService.md +++ b/doc/NavigationService.md @@ -1,5 +1,7 @@ # Navigation Service + ## Introduction + The navigation ble service provides 4 characteristics to allow the watch to display navigation instructions from a companion application. This service is intended to be used when performing some outdoor activities, for example running or cycling. The 4 characteristics are: @@ -9,110 +11,117 @@ 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 00010000-78fc-48fe-8e23-433b3a1942d0 ## Characteristics + ## 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 list of supported icon names. ## 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 00010003-78fc-48fe-8e23-433b3a1942d0) + This is a short string describing the distance to the upcoming instruction such as "50 m". ## 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 -* arrive -* arrive-left -* arrive-right -* arrive-straight -* close -* continue -* continue-left -* continue-right -* continue-slight-left -* continue-slight-right -* continue-straight -* continue-uturn -* depart -* depart-left -* depart-right -* depart-straight -* end-of-road-left -* end-of-road-right -* ferry -* flag -* fork -* fork-left -* fork-right -* fork-slight-left -* fork-slight-right -* fork-straight -* invalid -* invalid-left -* invalid-right -* invalid-slight-left -* invalid-slight-right -* invalid-straight -* invalid-uturn -* merge-left -* merge-right -* merge-slight-left -* merge-slight-right -* merge-straight -* new-name-left -* new-name-right -* new-name-sharp-left -* new-name-sharp-right -* new-name-slight-left -* new-name-slight-right -* new-name-straight -* notification-left -* notification-right -* notification-sharp-left -* notification-sharp-right -* notification-slight-left -* notification-slight-right -* notification-straight -* off-ramp-left -* off-ramp-right -* off-ramp-sharp-left -* off-ramp-sharp-right -* off-ramp-slight-left -* off-ramp-slight-right -* off-ramp-straight -* on-ramp-left -* on-ramp-right -* on-ramp-sharp-left -* on-ramp-sharp-right -* on-ramp-slight-left -* on-ramp-slight-right -* on-ramp-straight -* rotary -* rotary-left -* rotary-right -* rotary-sharp-left -* rotary-sharp-right -* rotary-slight-left -* rotary-slight-right -* rotary-straight -* roundabout -* roundabout-left -* roundabout-right -* roundabout-sharp-left -* roundabout-sharp-right -* roundabout-slight-left -* roundabout-slight-right -* roundabout-straight -* turn-left -* turn-right -* turn-sharp-left -* turn-sharp-right -* turn-slight-left -* turn-slight-right -* turn-stright -* updown -* uturn + +- arrive +- arrive-left +- arrive-right +- arrive-straight +- close +- continue +- continue-left +- continue-right +- continue-slight-left +- continue-slight-right +- continue-straight +- continue-uturn +- depart +- depart-left +- depart-right +- depart-straight +- end-of-road-left +- end-of-road-right +- ferry +- flag +- fork +- fork-left +- fork-right +- fork-slight-left +- fork-slight-right +- fork-straight +- invalid +- invalid-left +- invalid-right +- invalid-slight-left +- invalid-slight-right +- invalid-straight +- invalid-uturn +- merge-left +- merge-right +- merge-slight-left +- merge-slight-right +- merge-straight +- new-name-left +- new-name-right +- new-name-sharp-left +- new-name-sharp-right +- new-name-slight-left +- new-name-slight-right +- new-name-straight +- notification-left +- notification-right +- notification-sharp-left +- notification-sharp-right +- notification-slight-left +- notification-slight-right +- notification-straight +- off-ramp-left +- off-ramp-right +- off-ramp-sharp-left +- off-ramp-sharp-right +- off-ramp-slight-left +- off-ramp-slight-right +- off-ramp-straight +- on-ramp-left +- on-ramp-right +- on-ramp-sharp-left +- on-ramp-sharp-right +- on-ramp-slight-left +- on-ramp-slight-right +- on-ramp-straight +- rotary +- rotary-left +- rotary-right +- rotary-sharp-left +- rotary-sharp-right +- rotary-slight-left +- rotary-slight-right +- rotary-straight +- roundabout +- roundabout-left +- roundabout-right +- roundabout-sharp-left +- roundabout-sharp-right +- roundabout-slight-left +- roundabout-slight-right +- roundabout-straight +- turn-left +- turn-right +- turn-sharp-left +- turn-sharp-right +- turn-slight-left +- turn-slight-right +- turn-stright +- updown +- uturn diff --git a/doc/PinetimeStubWithNrf52DK.md b/doc/PinetimeStubWithNrf52DK.md index afa8a74d44d87b2b1bed286b8ad5c533905fe339..6fa0d5452c93d6a387428dc88f5d0af760e22a48 100644 --- a/doc/PinetimeStubWithNrf52DK.md +++ b/doc/PinetimeStubWithNrf52DK.md @@ -1,33 +1,36 @@ # Build a stub for PineTime using NRF52-DK + [NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official development kit for the NRF52832 SoC from Nordic Semiconductor used in the PineTime. This development kit can be very useful for PineTime development: - * You can use its embedded JLink SWD programmer/debugger to program and debug your code on the PineTime - * As it's based on the same SoC than the PineTime, you can program it to actually run the same code as the PineTime. - + +- You can use its embedded JLink SWD programmer/debugger to program and debug your code on the PineTime +- As it's based on the same SoC than the PineTime, you can program it to actually run the same code as the PineTime. + This page is about the 2nd point. We will build a stub that will allow us to run the same code you can run on the PineTime. This will allow you to work more easily if you don't have a PineTime dev kit around, if you don't want to modify your dev kit for SWD programming, or if you want to use some feature from the NRF52-DK (like power measurement). -This stub only implements the display, the button and the BLE radio. The other features from the pintime are missing: - * heart rate sensor - * SPI flash - * touchpad - * accelerometer +This stub only implements the display, the button and the BLE radio. The other features from the pintime are missing: + +- heart rate sensor +- SPI flash +- touchpad +- accelerometer These devices could be added on this stub, but I do not have the parts to try them out for now.  - Here are the parts you need to build this simulator: - * [NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) - * An ST7889 display (I bought [this one](https://www.aliexpress.com/item/32859772356.html?spm=a2g0s.9042311.0.0.1b774c4dSoc4Xz)) - * A push-button (the one I use comes from a previous project build around ESP8266 board Wemos D1 Mini). - * Dupont wires - + +- [NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) +- An ST7889 display (I bought [this one](https://www.aliexpress.com/item/32859772356.html?spm=a2g0s.9042311.0.0.1b774c4dSoc4Xz)) +- A push-button (the one I use comes from a previous project build around ESP8266 board Wemos D1 Mini). +- Dupont wires + You just need to make the following connections: | NRF52-DK | ST7889 display | -| ---------|--------------- | +| -------- | -------------- | | VDD | VCC | | GND | GND | | P0.03 | SDA | @@ -35,11 +38,10 @@ | P0.26 | RES | | P0.02 | SCL | | P0.18 | DC | - -| NRF52-DK | Push Button | -| ---------|----------------------- | -| P0.13 | Button IN (D3 in my case) | -| GND | GND | +| NRF52-DK | Push Button | +| -------- | ------------------------- | +| P0.13 | Button IN (D3 in my case) | +| GND | GND | You also need to enable the I/O expander to disconnect pins from the buttons and LED on the NRF52-DK and leave them available on the pin headers: @@ -47,4 +49,4 @@ | NRF52 -DK | NRF52- DK | | --------- | --------- | | DETECT | GND | -Now, you should be able to program the SoC on the NRF52-DK board, and use it as if it was running on the PineTime. \ No newline at end of file +Now, you should be able to program the SoC on the NRF52-DK board, and use it as if it was running on the PineTime. diff --git a/doc/SPI-LCD-driver.md b/doc/SPI-LCD-driver.md index 29f3bbfadec9dcb984883f63ee8bf04e5e38e759..758b4d6932ae1c09b10cf7f83f564eeef8356d8d 100644 --- a/doc/SPI-LCD-driver.md +++ b/doc/SPI-LCD-driver.md @@ -1,16 +1,20 @@ # The SPI LCD driver + ## Introduction + The LCD controller that drives the display of the Pinetime is the [Sitronix ST7789V](https://wiki.pine64.org/images/5/54/ST7789V_v1.6.pdf). This controller is easy to integrate with an MCU thanks to its SPI interface, and has some interesting features like: + - an on-chip display data RAM that can store the whole framebuffer - partial screen update - hardware assisted vertical scrolling -- interrupt pin, allowing to drive the display with DMA and IRQ +- interrupt pin, allowing to drive the display with DMA and IRQ - ... When you want to write a device driver for a specific component, its datasheet is your holy bible. This document contains a lot of information about the chip, its specification, characteristics, features and functionalities. -Luckily for us, the datasheet of the ST7789 is great! It contains everything we need to write a nice driver for our beloved Pinetime. +Luckily for us, the datasheet of the ST7789 is great! It contains everything we need to write a nice driver for our beloved Pinetime. In this document, I'll try to explain the process I've followed to write a device driver for the LCD. There were multiple iterations: + - First, I tried to find the correct initialization sequence so that the controller is configured correctly according to the hardware configuration; - Then, I tried to display some pixels on the screen; - Next, I wanted to display squares, colors and text; @@ -20,19 +24,20 @@ I'll describe all these steps in the following chapters. ## The datasheet + As I said in the introduction, the datasheet will be your bedside book during your journey as a device driver designer. You'll read it from the beginning to the end once, twice, maybe ten times. Then, each time you'll want to do something new, you'll reopen the file and search for that specific paragraph or diagram than explains how the controller works so that you can figure out how to use it. The schematic of your board (the Pinetime schematics in this case) will also be very important, as you'll need to know how the LCD controller is physically connected to the MCU. How to read the datasheet? I recommend to read it from the beginning to the end (no joke) at least once. You certainly do not need to read everything in details, but it's good to know what information is available and where in the document. It'll be very useful during the development phase. You'll want to read some part with more attention : + - Data color coding in 4-Line Serial Interface : how to send the pixel to be display to the controller - Display Data Ram : how is the memory organized - Power On/Off sequence - System function commands : all the commands you can send to the controller. ## One Pixel at a time - ## Bulk transfers @@ -41,6 +46,7 @@ ## IRQ ## Bare metal integration + Integration customisée dans la lib GFX que j'ai écrite -## Integration with LittleVGL \ No newline at end of file +## Integration with LittleVGL diff --git a/doc/SWD.md b/doc/SWD.md index 86e27517b8593bd53691bf688443d4807ab9922a..7fc869584b648839c3feb75b04761226e1c07b2c 100644 --- a/doc/SWD.md +++ b/doc/SWD.md @@ -1,4 +1,5 @@ # How to flash InfiniTime using the SWD interface + Download the files **bootloader.bin**, **image-x.y.z.bin** and **pinetime-graphics-x.y.z.bin** from the release page:  @@ -8,7 +9,7 @@ Using your SWD tool, flash **pinetime-graphics-x.y.z.bin** at offset **0x0000**. Reset the MCU and wait for a few seconds until the logo is completely drawn on the display. Then, using your SWD tool, flash these file at the following offsets: - - bootloader.bin : **0x0000** - - image-x.y.z.bin : **0x8000** +- bootloader.bin : **0x0000** +- image-x.y.z.bin : **0x8000** Reset and voilà, you're running InfiniTime on your PineTime! diff --git a/doc/ble.md b/doc/ble.md index bd9e66f5a9cc4fd85ab62f10a1f92f3d6fcdfe77..9c170418caa096a3bd1a45f8e9e298c73b5390cc 100644 --- a/doc/ble.md +++ b/doc/ble.md @@ -1,5 +1,7 @@ -# Bluetooth Low-Energy : +# Bluetooth Low-Energy : + ## Introduction + This page describes the BLE implementation and API built in this firmware. --- @@ -38,6 +40,7 @@ --- ## BLE Connection + When starting, the firmware starts BLE advertising. It sends small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices. A companion application (running on a PC, Raspberry Pi, smartphone, etc.) which receives this advertising packet can request a connection to the device. This connection procedure allows the 2 devices to negotiate communication parameters, security keys, etc. @@ -58,7 +61,8 @@ --- ## BLE UUIDs -When possible, InfiniTime tries to implement BLE services defined by the BLE specification. + +When possible, InfiniTime tries to implement BLE services defined by the BLE specification. When the service does not exist in the BLE specification, InfiniTime implements custom services. Custom services are identified by a UUID, as are all BLE services. Here is how to define the UUID of custom services in InfiniTime: @@ -70,34 +74,38 @@ ``` The following custom services are implemented in InfiniTime: - - Since InfiniTime 0.8: - * Music Service : 00000000-78fc-48fe-8e23-433b3a1942d0 - +- Since InfiniTime 0.8: - - Since InfiniTime 0.11: - * [Navigation Service](NavigationService.md) : 00010000-78fc-48fe-8e23-433b3a1942d0 + - Music Service : `00000000-78fc-48fe-8e23-433b3a1942d0` +- Since InfiniTime 0.11: + + - [Navigation Service](NavigationService.md) : `00010000-78fc-48fe-8e23-433b3a1942d0` - Since InfiniTime 0.13 - * Call characteristic (extension to the Alert Notification Service): 00020001-78fc-48fe-8e23-433b3a1942d0 + - Call characteristic (extension to the Alert Notification Service): `00020001-78fc-48fe-8e23-433b3a1942d0` - Since InfiniTime 1.7: - * [Motion Service](MotionService.md): 00030000-78fc-48fe-8e23-433b3a1942d0 + - [Motion Service](MotionService.md): `00030000-78fc-48fe-8e23-433b3a1942d0` - Since InfiniTime 1.8: - * [Weather Service](/src/components/ble/weather/WeatherService.h): 00040000-78fc-48fe-8e23-433b3a1942d0 + + - [Weather Service](/src/components/ble/weather/WeatherService.h): `00040000-78fc-48fe-8e23-433b3a1942d0` --- ## BLE services + [List of standard BLE services](https://www.bluetooth.com/specifications/gatt/services/) ### CTS + [Current Time Service](https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.current_time.xml) ### ANS + [Alert Notification Service](https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.alert_notification.xml)  diff --git a/doc/branches.md b/doc/branches.md index c12c764afdd20607daefbb1d531082dff50da7d5..cf98684b205d0f8e0eef733084a1bade476bc223 100644 --- a/doc/branches.md +++ b/doc/branches.md @@ -1,12 +1,14 @@ # Branches + The branching model of this project is based on the workflow named [Git flow](https://nvie.com/posts/a-successful-git-branching-model/). The project is based on 2 main branches: - - **master** : this branch is always ready to be deployed. It means that at any time, we should be able to build the branch and release a new version of the application. - - **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable. + +- **master** : this branch is always ready to be deployed. It means that at any time, we should be able to build the branch and release a new version of the application. +- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable. New features should be implemented in **feature branches** created from **develop**. When the feature is ready, a pull-request is created and it'll be merge into **develop** when it is successfully reviewed and accepted. To release a new version of the application, when develop is considered stable, a **release** branch is created from **develop**. This can be considered as a *release candidate* branch. When everything is OK, this release branch is merged into **master** and the release is generated (a tag is applied to git, the release note is finalized, binaries are built,...) from **master**. -Git flow also supports the creation of **hotfix** branches when a bug is discovered in a released version. The **hotfix** branch is created from **master** and will be used only to implement a fix to this bug. Multiple hotfix branches can be created for the same release if multiple bugs are discovered. \ No newline at end of file +Git flow also supports the creation of **hotfix** branches when a bug is discovered in a released version. The **hotfix** branch is created from **master** and will be used only to implement a fix to this bug. Multiple hotfix branches can be created for the same release if multiple bugs are discovered. diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md index 510f053dc7d324c4b8b33e552d0f27334351c359..58d0f72e3b3b42891f898e07e850f76544f9acee 100644 --- a/doc/buildAndProgram.md +++ b/doc/buildAndProgram.md @@ -1,24 +1,29 @@ # Build + ## Dependencies + To build this project, you'll need: - - A cross-compiler : [ARM-GCC (10.3-2021.10)](https://developer.arm.com/downloads/-/gnu-rm) - - The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip) - - The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt)) - - To keep the system clean, you can install python modules into a python virtual environment (`venv`) - ```sh - python -m venv .venv - source .venv/bin/activate - python -m pip install wheel - python -m pip install -r tools/mcuboot/requirements.txt - ``` - - A reasonably recent version of CMake (I use 3.16.5) - - lv_font_conv, to generate the font .c files - - see [lv_font_conv](https://github.com/lvgl/lv_font_conv#install-the-script) - - install npm (commonly done via the package manager, ensure node's version is at least 12) - - install lv_font_conv: `npm install lv_font_conv` + +- A cross-compiler : [ARM-GCC (10.3-2021.10)](https://developer.arm.com/downloads/-/gnu-rm) +- The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip) +- The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt)) + - To keep the system clean, you can install python modules into a python virtual environment (`venv`) + ```sh + python -m venv .venv + source .venv/bin/activate + python -m pip install wheel + python -m pip install -r tools/mcuboot/requirements.txt + ``` +- A reasonably recent version of CMake (I use 3.16.5) +- lv_font_conv, to generate the font .c files + - see [lv_font_conv](https://github.com/lvgl/lv_font_conv#install-the-script) + - install npm (commonly done via the package manager, ensure node's version is at least 12) + - install lv_font_conv: `npm install lv_font_conv` ## Build steps + ### Clone the repo + ``` git clone https://github.com/InfiniTimeOrg/InfiniTime.git cd InfiniTime @@ -26,7 +31,9 @@ git submodule update --init mkdir build cd build ``` + ### Project generation using CMake + CMake configures the project according to variables you specify the command line. The variables are: Variable | Description | Example| @@ -41,31 +48,36 @@ **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` **TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY-TFK5, MOY-TIN5, MOY-TON5, MOY-UNK`|`-DTARGET_DEVICE=PINETIME` (Default) -####(**) Note about **CMAKE_BUILD_TYPE**: +#### (\*) 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/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/InfiniTimeOrg/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory. -####(**) Note about **BUILD_DFU**: +#### (\*\*) Note about **BUILD_DFU** DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mechanism. 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. #### CMake command line for JLink + ``` cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_JLINK=1 -DNRFJPROG=... ../ ``` #### CMake command line for GDB Client (Black Magic Probe) + ``` cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_GDB_CLIENT=1 -DGDB_CLIENT_BIN_PATH=... -DGDB_CLIENT_TARGET_REMOTE=... ../ ``` #### CMake command line for OpenOCD + ``` cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] ../ ``` ### Build the project + During the project generation, CMake created the following targets: + - **FLASH_ERASE** : mass erase the flash memory of the NRF52. - **FLASH_pinetime-app** : flash the firmware into the NRF52. - **pinetime-app** : build the standalone (without bootloader support) version of the firmware. @@ -78,58 +90,69 @@ If you just want to build the project and run it on the Pinetime, using *pinetime-app* is recommended. See [this page](../bootloader/README.md) for more info about bootloader support. Build: + ``` make -j pinetime-app ``` List of files generated: Binary files are generated into the folder `src`: - - **pinetime-app.bin, .hex and .out** : standalone firmware in bin, hex and out formats. - - **pinetime-app.map** : map file - - **pinetime-mcuboot-app.bin, .hex and .out** : firmware with bootloader support in bin, hex and out formats. - - **pinetime-mcuboot-app.map** : map file - - **pinetime-mcuboot-app-image** : MCUBoot image of the firmware - - **pinetime-mcuboot-ap-dfu** : DFU file of the firmware + +- **pinetime-app.bin, .hex and .out** : standalone firmware in bin, hex and out formats. +- **pinetime-app.map** : map file +- **pinetime-mcuboot-app.bin, .hex and .out** : firmware with bootloader support in bin, hex and out formats. +- **pinetime-mcuboot-app.map** : map file +- **pinetime-mcuboot-app-image** : MCUBoot image of the firmware +- **pinetime-mcuboot-ap-dfu** : DFU file of the firmware -The same files are generated for **pinetime-recovery** and **pinetime-recoveryloader** +The same files are generated for **pinetime-recovery** and **pinetime-recoveryloader** - ### Program and run #### Using CMake targets + These target have been configured during the project generation by CMake according to the parameters you provided to the command line. Mass erase: + ``` make FLASH_ERASE -``` +``` Flash the application: + ``` make FLASH_pinetime-app ``` ### How to generate files needed by the factory + These files are needed by the Pine64 factory to flash InfiniTime as the default firmware on the PineTimes. Two files are needed: an **HEX (.hex)** file that contains the content of the internal flash memory (bootloader + InfiniTime) and a **binary (.bin)** file that contains the content of the external flash memory (recovery firmware). #### merged-internal.hex + First, convert the bootloader to hex: - ``` - <ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex ./bootloader.bin ./bootloader.hex - ``` + +``` +<ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex ./bootloader.bin ./bootloader.hex +``` + where `bootloader.bin` is the [last stable version](https://github.com/JF002/pinetime-mcuboot-bootloader/releases) of the [bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader). Then, convert the MCUBoot image of InfiniTime: + ``` <ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex --change-addresses 0x8000 ./pinetime-mcuboot-app-image-1.6.0.bin ./pinetime-mcuboot-app-image-1.6.0.hex ``` + where `pinetime-mcuboot-app-image-1.6.0.bin` is [the bin of the last MCUBoot image](https://github.com/InfiniTimeOrg/InfiniTime/releases) of [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime). Pay attention to the parameter `--change-addresses 0x8000`. It's needed to ensure the image will be flashed at the offset expected by the bootloader (0x8000). Finally, merge them together with **mergehex**: + ``` /opt/mergehex/mergehex -m ./bootloader.hex ./pinetime-mcuboot-app-image-1.6.0.hex -o merged-internal.hex ``` @@ -137,4 +160,5 @@ This file must be flashed at offset **0x00** of the internal memory of the NRF52832. #### spinor.bin + This file is the MCUBoot image of the last stable version of the recovery firmware. It must be flashed at offset **0x00** of the external SPINOR flash memory. diff --git a/doc/buildWithDocker.md b/doc/buildWithDocker.md index 1bea838025f02e8b00751db492abd35c584d948c..20bf85d48c5a5c8db2a95a098936178c00590769 100644 --- a/doc/buildWithDocker.md +++ b/doc/buildWithDocker.md @@ -1,24 +1,24 @@ # Build the project using Docker -A [Docker image (Dockerfile)](../docker) containing all the build environment is available for X86_64 and AMD64 architectures. +A [Docker image (Dockerfile)](../docker) containing all the build environment is available for X86_64 and AMD64 architectures. These images make the build of the firmware and the generation of the DFU file for OTA quite easy, as well as preventing clashes with any other toolchains or development environments you may have installed. Based on Ubuntu 22.04 with the following build dependencies: -* ARM GCC Toolchain -* nRF SDK -* MCUBoot -* adafruit-nrfutil -* lv_font_conv +- ARM GCC Toolchain +- nRF SDK +- MCUBoot +- adafruit-nrfutil +- lv_font_conv ## Run a container to build the project -The `infinitime-build` image contains all the dependencies you need. +The `infinitime-build` image contains all the dependencies you need. The default `CMD` will compile sources found in `/sources`, so you need only mount your code. Before continuing, make sure you first build the image as indicated in the [Build the image](#build-the-image) section, or check the [Using the image from Docker Hub](#using-the-image-from-docker-hub) section if you prefer to use a pre-made image. -This example will build the firmware, generate the MCUBoot image and generate the DFU file. +This example will build the firmware, generate the MCUBoot image and generate the DFU file. For cloning the repo, see [these instructions](../doc/buildAndProgram.md#clone-the-repo). Outputs will be written to **<project_root>/build/output**: ```bash @@ -26,12 +26,12 @@ cd# e.g. cd ./work/Pinetime docker run --rm -it -v ${PWD}:/sources --user $(id -u):$(id -g) infinitime-build ``` -By default, the container runs as `root`, which is not convenient as all the files generated by the build will also belong to `root`. -The parameter `--user` overrides that default behavior. -The command above will run as your current user. +By default, the container runs as `root`, which is not convenient as all the files generated by the build will also belong to `root`. +The parameter `--user` overrides that default behavior. +The command above will run as your current user. -If you only want to build a single CMake target, you can pass it in as the first parameter to the build script. -This means calling the script explicitly as it will override the `CMD`. +If you only want to build a single CMake target, you can pass it in as the first parameter to the build script. +This means calling the script explicitly as it will override the `CMD`. Here's an example for `pinetime-app`: ```bash @@ -50,9 +50,9 @@ ``` The default `latest` tag *should* automatically identify the correct image architecture, but if for some reason Docker does not, you can specify it manually: -* For AMD64 (x86_64) systems: `docker pull --platform linux/amd64 infinitime/infinitime-build` +- For AMD64 (x86_64) systems: `docker pull --platform linux/amd64 infinitime/infinitime-build` -* For ARM64v8 (ARM64/aarch64) systems: `docker pull --platform linux/arm64 infinitime/infinitime-build` +- For ARM64v8 (ARM64/aarch64) systems: `docker pull --platform linux/arm64 infinitime/infinitime-build` ## Build the image @@ -62,4 +62,4 @@ The following commands must be run from the root of the project. This operation will take some time but, when done, a new image named *infinitime-build* is available. ```bash docker build -t infinitime-build ./docker -``` \ No newline at end of file +``` diff --git a/doc/buildWithVScode.md b/doc/buildWithVScode.md index 48b8923f0a3e6c32dd4fe21c8ddc80f65f5e1366..8e136511d0e73be8da1845286aa93c8e1e3f8358 100644 --- a/doc/buildWithVScode.md +++ b/doc/buildWithVScode.md @@ -26,27 +26,22 @@ [Cortex-Debug](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) - ARM Cortex-M GDB Debugger support for VS Code Cortex-Debug is only required for interactive debugging using VS Codes built in GDB support. - - ## VS Code/Docker DevContainer The .devcontainer folder contains the configuration and scripts for using a Docker dev container for building InfiniTime -Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension is recommended. It will handle configuring the Docker virtual machine and setting everything up. +Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension is recommended. It will handle configuring the Docker virtual machine and setting everything up. -More documentation is available in the [readme in .devcontainer](.devcontainer/readme.md) +More documentation is available in the [readme in .devcontainer](.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. +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 index f067b58b4aaf1fdd8012cc4ac56d197de2e0a356..c756a8b4e415f4c6356cb4d69340687008cfa9d7 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -1,5 +1,7 @@ # Apps + This page will teach you: + - what screens and apps are in InfiniTime - how to implement your own app @@ -14,6 +16,7 @@ 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. @@ -24,10 +27,12 @@ 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 function for reference. ### Continuous updating + If your app needs to be updated continuously, you 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: + ```cpp taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); ``` @@ -37,9 +42,11 @@ Remember to delete the task again using `lv_task_del`. The function `RefreshTaskCallback` is inherited from `Screen` and just calls your `Refresh` function. ## Creating your own app + A minimal app could look like this: MyApp.h: + ```cpp #pragma once @@ -60,6 +67,7 @@ } ``` MyApp.cpp: + ```cpp #include "displayapp/screens/MyApp.h" #include "displayapp/DisplayApp.h" @@ -77,6 +85,7 @@ 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. diff --git a/doc/code/Intro.md b/doc/code/Intro.md index 23b3ade17b6a6435993d34edbd0c1609c88820eb..34adc5fa6c0c0e95b1aeab2024ab5e9d1496f2f7 100644 --- a/doc/code/Intro.md +++ b/doc/code/Intro.md @@ -1,7 +1,9 @@ # 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. @@ -12,6 +14,7 @@ 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**. @@ -29,6 +32,7 @@ it will need instead of just typing in a large-ish number. You can use `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. @@ -37,7 +41,9 @@ 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/coding-convention.md b/doc/coding-convention.md index 7198fa4f6fb63a291470eb95952f4b549bbca199..9d218ba29e2b42556869199aaf90fd35b7cf8a59 100644 --- a/doc/coding-convention.md +++ b/doc/coding-convention.md @@ -1,41 +1,29 @@ -# Coding convention - -## Language - -The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction. - -C code is accepted if it comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK. +# Coding style -## Coding style +## Use these tools to find and fix issues. -The most important rule to follow is to try to keep the code as easy to read and maintain as possible. +- Use `clang-format` to format the code. +- Use `clang-tidy` to check the code for other potential issues. -Using an autoformatter is highly recommended, but make sure it's configured properly. +## Follow these guidelines while writing code. -There are preconfigured autoformatter rules for: - - * CLion (IntelliJ) in [.idea/codeStyles/Project.xml](/.idea/codeStyles/Project.xml) - * `clang-format` - -Also use `clang-tidy` to check the code for other issues. - -If there are no preconfigured rules for your IDE, you can use one of the existing ones to configure your IDE. - - - **Indentation** : 2 spaces, no tabulation - - **Opening brace** at the end of the line - - **Naming** : Choose self-describing variable name - - **class** : PascalCase - - **namespace** : PascalCase - - **variable** : camelCase, **no** prefix/suffix ('_', 'm_',...) for class members - - **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`) - - **Includes** : - - files from the project : `#include "relative/path/to/the/file.h"` - - external files and std : `#include <file.h>` - - use includes relative to included directories like `src`, not relative to the current file. Don't do: `#include "../file.h"` - - Only use [primary spellings for operators and tokens](https://en.cppreference.com/w/cpp/language/operator_alternative) - - Use auto sparingly. Don't use auto for [fundamental/built-in types](https://en.cppreference.com/w/cpp/language/types) and [fixed width integer types](https://en.cppreference.com/w/cpp/types/integer), except when initializing with a cast to avoid duplicating the type name. - - Examples: - - `auto* app = static_cast<DisplayApp*>(instance);` - - `auto number = static_cast<uint8_t>(variable);` - - `uint8_t returnValue = MyFunction();` - - Use nullptr instead of NULL +- **Indentation** : 2 spaces, no tabulation +- **Opening brace** at the end of the line +- **Naming** : Choose self-describing variable name + - **class** : PascalCase + - **namespace** : PascalCase + - **variable** : camelCase, **no** prefix/suffix (`_`, `m_`,...) for class members +- **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`) +- **Includes** : + - files from the project : `#include "relative/path/to/the/file.h"` + - external files and std : `#include <file.h>` + - use includes relative to included directories like `src`, not relative to the current file. Don't do: `#include "../file.h"` +- Only use [primary spellings for operators and tokens](https://en.cppreference.com/w/cpp/language/operator_alternative) +- Use `auto` sparingly. Don't use `auto` for [fundamental/built-in types](https://en.cppreference.com/w/cpp/language/types) and [fixed width integer types](https://en.cppreference.com/w/cpp/types/integer), except when initializing with a cast to avoid duplicating the type name. + ```c++ + // Examples: + auto* app = static_cast<DisplayApp*>(instance); + auto number = static_cast<uint8_t>(variable); + uint8_t returnValue = MyFunction(); + ``` +- Use `nullptr` instead of `NULL` diff --git a/doc/contribute.md b/doc/contribute.md index f2a4aeaa7b48201e07a6c9e140e75d298b4450a7..f4e241a107e68c8b2dc30af1f4002caef2bfc707 100644 --- a/doc/contribute.md +++ b/doc/contribute.md @@ -1,61 +1,19 @@ # How to contribute? -## Report bugs - -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 - -Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, photo, video,... - -As the documentation is part of the source code, you can submit your improvements to the documentation by submitting a pull request (see below). - -## Fix bugs, add functionalities and improve the code - -You want to fix a bug, add a cool new functionality or improve the code? See *How to submit a pull request below*. - -# How to submit a pull request? +- [Report bugs](https://github.com/InfiniTimeOrg/InfiniTime/issues/new?assignees=&labels=bug&template=bug-report.yaml) +- Write and improve documentation + - Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, videos,... + - As the documentation is part of the source code, you can submit changes to the documentation by creating a pull request (see below) +- Fix bugs, add functionalities and improve the code + - See *How to create a pull request* below -## TL;DR +## How to create a pull request? - - 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 your code against the [coding conventions](/doc/coding-convention.md) 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 :) +1. Fork the project, create a [feature branch](branches.md) from develop and give it a short name that explains the topic of your changes + - Any feature branch should focus on one topic only +2. Make changes in this branch + - Write code that satisfies the [coding conventions](/doc/coding-convention.md) + - Test your changes on a PineTime or the [InfiniTime simulator](https://github.com/InfiniTimeOrg/InfiniSim) +3. Create a pull request, participate in the discussion and make more changes to the feature branch if necessary Your contributions are more than welcome! - -If you want to fix a bug, add functionality or improve the code, you'll first need to create a branch from the **develop** branch (see [this page about the branching model](./branches.md)). This branch is called a feature branch, and you should choose a name that explains what you are working on (ex: "add-doc-about-contributions"). In this branch, **focus on only one topic, bug or feature**. For example, if you created this branch to work on the UI of a specific application, do not commit modifications about the SPI driver. If you want to work on multiple topics, create one branch for each topic. - -When your feature branch is ready, **make sure it actually works** and **do not forget to write documentation** about it if it's relevant. - -**Creating a pull request containing modifications that haven't been tested is strongly discouraged.** If for any reason you cannot test your modifications, but want to publish them anyway, **please mention it in the description**. This way, other contributors might be willing to test it and provide feedback about your code. - -Before submitting a PR, check your code against the [coding conventions](/doc/coding-convention.md). This project also provides [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy) configuration files. You should use them to ensure correct formatting of your code. - -Don't forget to check the files you are going to commit and remove those which aren't necessary (config files from your IDE, for example). Remove old comments, commented code,... - -Then, you can submit a pull request for review. Try to **describe your pull request as much as possible**: what did you do in this branch, how does it work, how it is designed, are there any limitations,... This will help the contributors to understand and review your code easily. You can add pictures and video to the description so that contributors will have a quick overview of your work. - -Other contributors can post comments about the pull request, maybe ask for more info or adjustments in the code. - -Once the pull request is reviewed and accepted, it'll be merged into **develop** and will be released in the next version of the firmware. - -## Why all these rules? - -Reviewing pull requests is a **very time consuming task**. Everything you do to make reviewing easier will **get your PR merged faster**. - -Reviewers will first look at the **description**. If it's easy to understand what the PR does, why the modification is needed or interesting and how it's done, a good part of the work is already done : we understand the PR and its context. - -Reviewing **a few files that were modified for a single purpose** is a lot easier than reviewing 30 files modified for many reasons (bug fix, UI improvements, typos in doc,...), even if all the changes make sense. Also, it's possible that we agree on some modification but not on another, so we won't be able to merge the PR because of the changes that are not accepted. - -The code base should be kept as consistent as possible. If the formatting of your code is not consistent with the rest of the code base, we'll ask you to review it. - -Lastly the changes are tested. If it doesn't work out of the box, we'll ask you to review your code and to ensure that it works as expected. - -It's totally normal for a PR to need some more work even after it was created, that's why we review them. But every round trip takes time, so it's good practice to try to reduce them as much as possible by following those simple rules. diff --git a/doc/filesInReleaseNotes.md b/doc/filesInReleaseNotes.md index 6a5873c0b72ed8d528bef9a85e0358811f248845..4cd0d3c5eb9d2b1f2bdc9517194095eba8282297 100644 --- a/doc/filesInReleaseNotes.md +++ b/doc/filesInReleaseNotes.md @@ -1,4 +1,5 @@ # Using the releases + 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. @@ -8,49 +9,52 @@ ## Files included in the release notes ### Standalone firmware + This firmware is standalone, meaning that it does not need a bootloader to actually run. It is intended to be flashed at offset 0, meaning it will erase any bootloader that might be present in memory. - - **pinetime-app.out** : Output file of GCC containing debug symbols, useful if you want to debug the firmware using GDB. - - **pinetime-app.hex** : Firmware in Intel HEX file format. Easier to use because it contains the offset in memory where it must be flashed, you don't need to specify it. - - **pintime-app.bin** : Firmware in binary format. When programming it, you have to specify the offset (0x00) in memory where it must be flashed. - - **pinetime-app.map** : Map file containing all the symbols, addresses in memory,... - +- **pinetime-app.out** : Output file of GCC containing debug symbols, useful if you want to debug the firmware using GDB. +- **pinetime-app.hex** : Firmware in Intel HEX file format. Easier to use because it contains the offset in memory where it must be flashed, you don't need to specify it. +- **pintime-app.bin** : Firmware in binary format. When programming it, you have to specify the offset (0x00) in memory where it must be flashed. +- **pinetime-app.map** : Map file containing all the symbols, addresses in memory,... + **This firmware must be flashed at address 0x00 in the main flash memory** ### Bootloader + The bootloader is maintained by [lupyuen](https://github.com/lupyuen) and is a binary version of [this release](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4). - - **bootloader.hex** : Firmware in Intel HEX file format. - - **This firmware must be flashed at address 0x00 in the main flash memory** +- **bootloader.hex** : Firmware in Intel HEX file format. + +**This firmware must be flashed at address 0x00 in the main flash memory** +### Graphics firmware -### Graphics firmware This firmware is a small utility firmware that writes the boot graphic in the external SPI flash memory. You need it if you want to use the [bootloader](../bootloader/README.md). - - **pinetime-graphics.out** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB. - - **pinetime-graphics.hex** : Firmware in Intel HEX file format. Easier to use because it contains the offset in memory where it must be flashed, you don't need to specify it. - - **pintime-graphics.bin** : Firmware in binary format. When programming it, you have to specify the offset (0x00) in memory where it must be flashed. - - **pinetime-graphics.map** : Map file containing all the symbols, addresses in memory,... - +- **pinetime-graphics.out** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB. +- **pinetime-graphics.hex** : Firmware in Intel HEX file format. Easier to use because it contains the offset in memory where it must be flashed, you don't need to specify it. +- **pintime-graphics.bin** : Firmware in binary format. When programming it, you have to specify the offset (0x00) in memory where it must be flashed. +- **pinetime-graphics.map** : Map file containing all the symbols, addresses in memory,... + **This firmware must be flashed at address 0x00 in the main flash memory** ### Firmware with bootloader + This firmware is intended to be used with our [MCUBoot-based bootloader](../bootloader/README.md). - - **pinetime-mcuboot-app-image.hex**: Firmware wrapped into an MCUBoot image. This is **the** file that must be flashed at **0x8000** into the flash memory. If the [bootloader](../bootloader/README.md) has been successfully programmed, it should run this firmware after the next reset. +- **pinetime-mcuboot-app-image.hex**: Firmware wrapped into an MCUBoot image. This is **the** file that must be flashed at **0x8000** into the flash memory. If the [bootloader](../bootloader/README.md) has been successfully programmed, it should run this firmware after the next reset. The following files are not directly usable by the bootloader: - - **pinetime-mcuboot-app.out** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB. - - **pinetime-mcuboot-app.hex** : Firmware in Intel HEX file format. - - **pinetime-mcuboot-app.bin** : Firmware in binary format. - - **pinetime-mcuboot-app.map** : Map file containing all the symbols, addresses in memory,... +- **pinetime-mcuboot-app.out** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB. +- **pinetime-mcuboot-app.hex** : Firmware in Intel HEX file format. +- **pinetime-mcuboot-app.bin** : Firmware in binary format. +- **pinetime-mcuboot-app.map** : Map file containing all the symbols, addresses in memory,... ### OTA (Update the firmware Over-The-Air) + Once the bootloader and application firmware are running, it is possible to update the current firmware or even replace it with another firmware **that uses the same bootloader based on MCUBoot**. **NOTE :** Use this file **only** if you programmed our [MCUBoot-based bootloader](../bootloader/README.md). This file is not compatible with other bootloaders like the one that is based on the closed source NRF SoftDevice ! - - **pinetime-app-dfu.zip** : This is the file you must provide toNRFConnect to update the firmware over BLE. - +- **pinetime-app-dfu.zip** : This is the file you must provide toNRFConnect to update the firmware over BLE. diff --git a/doc/gdb.md b/doc/gdb.md index eb9b73f1c44b1cdada78035a62989e8e3376fbec..209ba652411aa14674c36947af91f6434de9fb5d 100644 --- a/doc/gdb.md +++ b/doc/gdb.md @@ -12,6 +12,7 @@ run ``` Example : + ``` $ /home/jf/nrf52/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-gdb @@ -45,4 +46,3 @@ Loading section .sec7, size 0xdf08 lma 0x40000 Start address 0x0, load size 314200 Transfer rate: 45 KB/sec, 969 bytes/write. ``` - diff --git a/doc/gettingStarted/about-software.md b/doc/gettingStarted/about-software.md index e935d938d43ace5dec918ccb0f3484de49b9ca6c..54bcaf141a831d3764357e00177bf8a044e753c0 100644 --- a/doc/gettingStarted/about-software.md +++ b/doc/gettingStarted/about-software.md @@ -6,9 +6,9 @@ A **firmware** is software running on the embedded hardware of a device. InfiniTime has three distinct firmwares: - - **[InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)** is the operating system. - - **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying firmware updates and runs before booting into InfiniTime. - - **The recovery firmware** is a special *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. +- **[InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)** is the operating system. +- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying firmware updates and runs before booting into InfiniTime. +- **The recovery firmware** is a special *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. **OTA** (**O**ver **T**he **A**ir) refers to updating of the firmware over BLE (**B**luetooth **L**ow **E**nergy). This is a functionality that allows the user to update the firmware on their device wirelessly. @@ -20,7 +20,7 @@ Most of the time, the bootloader just runs without your intervention (updating and loading the firmware). However, you can use the bootloader to rollback to the previous firmware, or load the recovery firmware using the push button: - - Press and hold the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the current one. - - Press and hold the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality. +- Press and hold the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the current one. +- Press and hold the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality. More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md). diff --git a/doc/gettingStarted/gettingStarted-1.0.md b/doc/gettingStarted/gettingStarted-1.0.md index 29433921b5974436a6c1e50ae1c5b72ad03f7ede..1586de562a0d0b59b2ab4023726df22ff11a66d9 100644 --- a/doc/gettingStarted/gettingStarted-1.0.md +++ b/doc/gettingStarted/gettingStarted-1.0.md @@ -12,9 +12,9 @@ By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00). You can sync the time using companion apps. - - Gadgetbridge automatically synchronizes the time when you connect it to your watch. More information on Gadgetbridge [here](/doc/gettingStarted/ota-gadgetbridge.md) - - [Sync the time with NRFConnect](/doc/gettingStarted/time-nrfconnect.md) - - Sync the time with your browser https://hubmartin.github.io/WebBLEWatch/ +- Gadgetbridge automatically synchronizes the time when you connect it to your watch. More information on Gadgetbridge [here](/doc/gettingStarted/ota-gadgetbridge.md) +- [Sync the time with NRFConnect](/doc/gettingStarted/time-nrfconnect.md) +- Sync the time with your browser https://hubmartin.github.io/WebBLEWatch/ You can also set the time in the settings without a companion app. (version >1.7.0) @@ -30,9 +30,9 @@ The indicator on the top left is visible if you have unread notifications On the top right there are status icons - - The battery icon shows roughly how much charge is remaining - - The Bluetooth icon is visible when the watch is connected to a companion app - - A plug icon is shown when the watch is plugged into a charger. +- The battery icon shows roughly how much charge is remaining +- The Bluetooth icon is visible when the watch is connected to a companion app +- A plug icon is shown when the watch is plugged into a charger. On the bottom left you can see your heart rate if you have the measurement enabled in the heart rate app. @@ -45,13 +45,13 @@    - - Swipe **up** to display the application menus. Apps (stopwatch, music, step, games,...) can be started from this menu. - - Swipe **down** to display the notification panel. Notification sent by your companion app will be displayed here. - - Swipe **right** to display the Quick Actions menu. This menu allows you to - - Set the brightness of the display - - Start the **flashlight** app - - Enable/disable notifications (Do Not Disturb mode) - - Enter the **settings** menu - - Swipe up and down to see all options - - Click the button to go back a screen. - - You can hold the button for a short time to return to the watch face. (version >1.7.0) +- Swipe **up** to display the application menus. Apps (stopwatch, music, step, games,...) can be started from this menu. +- Swipe **down** to display the notification panel. Notification sent by your companion app will be displayed here. +- Swipe **right** to display the Quick Actions menu. This menu allows you to + - Set the brightness of the display + - Start the **flashlight** app + - Enable/disable notifications (Do Not Disturb mode) + - Enter the **settings** menu + - Swipe up and down to see all options +- Click the button to go back a screen. +- You can hold the button for a short time to return to the watch face. (version >1.7.0) diff --git a/doc/gettingStarted/ota-nrfconnect.md b/doc/gettingStarted/ota-nrfconnect.md index 800bd6bc96d1f03bfd628a640d6538332ac6a28e..292e7fc4d0d9eead8dbfdee48a54daa3d9e2afd8 100644 --- a/doc/gettingStarted/ota-nrfconnect.md +++ b/doc/gettingStarted/ota-nrfconnect.md @@ -19,4 +19,5 @@  # Demo + [This video](https://seafile.codingfield.com/f/a52b69683a05472a90c7/) shows how to use NRFConnect to update the firmware running on the Pinetime. diff --git a/doc/gettingStarted/updating-software.md b/doc/gettingStarted/updating-software.md index 7a05073ab48e6ef7cdebcdb9c59f3b24ed2ee6d1..d302607e295f48cf6be32d96ca09626bf5de20f2 100644 --- a/doc/gettingStarted/updating-software.md +++ b/doc/gettingStarted/updating-software.md @@ -26,8 +26,8 @@ To update the firmware, you need to download the DFU of the firmware version that you'd like to install, for example `pinetime-mcuboot-app-dfu-1.6.0.zip`, and flash it with your companion app. We have prepared instructions for flashing InfiniTime with Gadgetbridge and NRFConnect. - - [Updating with Gadgetbridge](/doc/gettingStarted/ota-gadgetbridge.md) - - [Updating with NRFConnect](/doc/gettingStarted/ota-nrfconnect.md) +- [Updating with Gadgetbridge](/doc/gettingStarted/ota-gadgetbridge.md) +- [Updating with NRFConnect](/doc/gettingStarted/ota-nrfconnect.md) ## Firmware validation @@ -35,7 +35,7 @@ Firmware updates must be manually validated. If the firmware isn't validated and the watch resets, the watch will revert to the previous firmware. This is a safety feature to prevent bricking your device with faulty firmware. You can validate your updated firmware on InfiniTime >= 1.0 by following this simple procedure: - - From the watchface, swipe **right** to display the *quick settings menu* - - Open settings by tapping the cogwheel on the bottom right - - Swipe up until you find an entry named **Firmware** and tap on it - - If the firmware is not validated yet, you can either validate the running firmware, or reset and revert to the previous firmware version +- From the watchface, swipe **right** to display the *quick settings menu* +- Open settings by tapping the cogwheel on the bottom right +- Swipe up until you find an entry named **Firmware** and tap on it +- If the firmware is not validated yet, you can either validate the running firmware, or reset and revert to the previous firmware version diff --git a/doc/jlink.md b/doc/jlink.md index eebcac4947fa0005c446f5302f32cc5f6a64437f..b69c4c46e8765f4d897c3706e991ee19f69729e8 100644 --- a/doc/jlink.md +++ b/doc/jlink.md @@ -1,6 +1,7 @@ # Flashing the firmware with JLink Start JLinkExe: + ``` $ /opt/SEGGER/JLink/JLinkExe -device nrf52 -if swd -speed 4000 -autoconnect 1 SEGGER J-Link Commander V6.70d (Compiled Apr 16 2020 17:59:37) @@ -43,6 +44,7 @@ J-Link> ``` Use the command loadfile to program the .hex file: + ``` J-Link>loadfile pinetime-app.hex Downloading file [pinetime-app.hex]... @@ -56,6 +58,7 @@ O.K. ``` Then reset (r) and start (g) the CPU: + ``` J-Link>r Reset delay: 0 ms @@ -66,17 +69,18 @@ J-Link>g ``` # JLink RTT + RTT is a feature from Segger's JLink devices that allows bidirectional communication between the debugger and the target. This feature can be used to get the logs from the embedded software on the development computer. - - Program the MCU with the code (see above) - - Start JLinkExe +- Program the MCU with the code (see above) +- Start JLinkExe ``` $ JLinkExe -device nrf52 -if swd -speed 4000 -autoconnect 1 ``` Start JLinkRTTClient + ``` $ JLinkRTTClient ``` - diff --git a/doc/logo/infinitime-logo-small.jpg b/doc/logo/infinitime-logo-small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9949f5b0d98dfd1a358a2574e00dd25d14b4fa70 Binary files /dev/null and b/doc/logo/infinitime-logo-small.jpg differ diff --git a/doc/logo/infinitime-logo.jpg b/doc/logo/infinitime-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..86a16f0b73a6a7992a34821c76239062c1a819e4 Binary files /dev/null and b/doc/logo/infinitime-logo.jpg differ diff --git a/doc/openOCD/pogopins.jpg b/doc/openOCD/pogopins.jpg new file mode 100644 index 0000000000000000000000000000000000000000..28a1c7fc58147cfb7d674136006f94f1d4361f60 Binary files /dev/null and b/doc/openOCD/pogopins.jpg differ diff --git a/doc/openOCD/swd_pinout.jpg b/doc/openOCD/swd_pinout.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1545916d021a7e41ca858fa9ad1c27948528cb72 Binary files /dev/null and b/doc/openOCD/swd_pinout.jpg differ diff --git a/doc/openOCD.md b/doc/openOCD.md index df24b30b2f284f218322a2de883e4922f6714bb0..34f6242542ec6fd0def723f47f44d311d07537a2 100644 --- a/doc/openOCD.md +++ b/doc/openOCD.md @@ -1,4 +1,5 @@ # OpenOCD and STLink + OpenOCD (**Open O**n **C**hip **D**ebugger) is an open source tool that interfaces with many SWD/JTAG debugger to provide debugging and *in-system* programming for embedded target devices. OpenOCD supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger. @@ -6,9 +7,10 @@ OpenOCD works on X86 computers, ARM/ARM64 computers, and SBCs (like the RaspberryPi and Pine64 Pinebook Pro)! ## Installation + We will build OpenOCD from sources, as packages from Linux distributions are most of the time outdated and do not support the NRF52 properly. - - Fetch the sources from GIT, and build and install it: +- Fetch the sources from GIT, and build and install it: ``` git clone https://git.code.sf.net/p/openocd/code openocd-code @@ -21,13 +23,14 @@ make -j 4 sudo make install ``` - - Configure UDEV to allow OpenOCD to open the interface to your STLinkV2: +- Configure UDEV to allow OpenOCD to open the interface to your STLinkV2: + ``` sudo cp contrib/60-openocd.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules ``` - - You can now plug your STLinkV2 into a USB port and run OpenOCD to see if it's working correctly: +- You can now plug your STLinkV2 into a USB port and run OpenOCD to see if it's working correctly: ``` $ openocd -f interface/stlink.cfg -f target/nrf52.cfg @@ -50,11 +53,14 @@ Info : STLINK V2J34S7 (API v2) VID:PID 0483:3748 Info : Target voltage: 3.294340 Error: init mode failed (unable to connect to the target) ``` + Ok, OpenOCD is running and it detects my STLinkV2. The last error shows that I've not connected the STLinkV2 to the PineTime. ## Configuration files + OpenOCD is configured using configuration files. First, we need a common configuration file for the project : **openocd-stlink.ocd**: + ``` source [find interface/stlink.cfg] @@ -63,11 +69,13 @@ gdb_breakpoint_override hard source [find target/nrf52.cfg] ``` + This file specifies to OpenOCD which debugger and target it will be connected to. Then, we use various *user files* to use OpenOCD to flash InfiniTime binary files. This files flashes the bootloader and the application firmware : **flash_bootloader_app.ocd**: + ``` init @@ -78,6 +86,7 @@ reset ``` And this one flashes the graphics flasher (it writes the bootloader graphics into the SPI NOR flash memory) : **flash_graphics.ocd**: + ``` init @@ -87,19 +96,23 @@ reset ``` ## Examples + ### Flash bootloader and application + ``` openocd -f ./openocd-stlink.ocd -f ./flash_bootloader_app.ocd ``` ### Flash graphics flasher + ``` openocd -f ./openocd-stlink.ocd -f ./flash_graphics.ocd ``` ## Connect the STLinkV2 to the PineTime + Here is an example using the pogo pins: - - + + You can find more information about the SWD wiring [on the wiki](https://wiki.pine64.org/index.php?title=PineTime_devkit_wiring). diff --git a/doc/ui_guidelines.md b/doc/ui_guidelines.md index 296497af7a836a05bf818e220513603ecaaaa259..1a93fadaf247d315af0279cb08c9b5784e6cdb21 100644 --- a/doc/ui_guidelines.md +++ b/doc/ui_guidelines.md @@ -5,9 +5,9 @@ - Buttons should generally be at least 50px high - Buttons should generally be on the bottom edge - Make interactable objects **big** - When using a page indicator, leave 8px for it on the right side - - It is acceptable to leave 8px on the left side as well to center the content + - It is acceptable to leave 8px on the left side as well to center the content - Top bar takes at least 20px + padding - - Top bar right icons move 8px to the left when using a page indicator + - Top bar right icons move 8px to the left when using a page indicator - A black background helps to hide the screen border, allowing the UI to look less cramped when utilizing the entire display area. - A switch should be twice as wide as it is tall. diff --git a/doc/versioning.md b/doc/versioning.md index 2fa36ab95481caf71cae418df2a93a3a15a7400a..28ca085cccf4e33327797d4bba949bbe4f8cea83 100644 --- a/doc/versioning.md +++ b/doc/versioning.md @@ -1,6 +1,7 @@ # Versioning + The versioning of this project is based on [Semantic versioning](https://semver.org/): - - The **patch** is incremented when a bug is fixed on a **released** version (most of the time using a **hotfix** branch). - - The **minor** is incremented when a new version with new features is released. 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. +- The **patch** is incremented when a bug is fixed on a **released** version (most of the time using a **hotfix** branch). +- The **minor** is incremented when a new version with new features is released. 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. diff --git a/docker/README.md b/docker/README.md index 71ad258ace32ad7ea7dd0526079c3f37af328b8b..5b897b2b013d10bdffd284e25e44884ea1cd6e4b 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,2 +1,2 @@ Docker images and build script for building the project using Docker. -See [this page for more info](../doc/buildWithDocker.md). \ No newline at end of file +See [this page for more info](../doc/buildWithDocker.md). diff --git a/images/0.14.0/collage1.png b/images/0.14.0/collage1.png deleted file mode 100644 index fd5f27bae94efa0ec9513133d4c572dad3dc82fa..0000000000000000000000000000000000000000 Binary files a/images/0.14.0/collage1.png and /dev/null differ diff --git a/images/0.14.0/collage2.png b/images/0.14.0/collage2.png deleted file mode 100644 index 293147dd92b4d373247bce575ec3c41fea92a4c7..0000000000000000000000000000000000000000 Binary files a/images/0.14.0/collage2.png and /dev/null differ diff --git a/images/0.7.0/montage.jpg b/images/0.7.0/montage.jpg deleted file mode 100644 index 81716cc9e79e7cc2f4cca286d90363030c3e5ecb..0000000000000000000000000000000000000000 Binary files a/images/0.7.0/montage.jpg and /dev/null differ diff --git a/images/1.0.0/collage.png b/images/1.0.0/collage.png deleted file mode 100644 index b9ffaa882d667a4dfc02589ff4e7e7d09a958233..0000000000000000000000000000000000000000 Binary files a/images/1.0.0/collage.png and /dev/null differ diff --git a/images/infinitime-logo-small.jpg b/images/infinitime-logo-small.jpg deleted file mode 100644 index 9949f5b0d98dfd1a358a2574e00dd25d14b4fa70..0000000000000000000000000000000000000000 Binary files a/images/infinitime-logo-small.jpg and /dev/null differ diff --git a/images/infinitime-logo.jpg b/images/infinitime-logo.jpg deleted file mode 100644 index 86a16f0b73a6a7992a34821c76239062c1a819e4..0000000000000000000000000000000000000000 Binary files a/images/infinitime-logo.jpg and /dev/null differ diff --git a/images/pinetime.jpg b/images/pinetime.jpg deleted file mode 100644 index 7f729fa5e2b3fd7218d6a615cb5a9002d49c9c2c..0000000000000000000000000000000000000000 Binary files a/images/pinetime.jpg and /dev/null differ diff --git a/images/pinetimestub1.jpg b/images/pinetimestub1.jpg deleted file mode 100644 index 3ebc34e5d114eebd272fd9919fca90d4ea2b8b09..0000000000000000000000000000000000000000 Binary files a/images/pinetimestub1.jpg and /dev/null differ diff --git a/images/pogopins.jpg b/images/pogopins.jpg deleted file mode 100644 index 28a1c7fc58147cfb7d674136006f94f1d4361f60..0000000000000000000000000000000000000000 Binary files a/images/pogopins.jpg and /dev/null differ diff --git a/images/swd_pinout.jpg b/images/swd_pinout.jpg deleted file mode 100644 index 1545916d021a7e41ca858fa9ad1c27948528cb72..0000000000000000000000000000000000000000 Binary files a/images/swd_pinout.jpg and /dev/null differ diff --git a/images/v0.3.0/Gauge.jpg b/images/v0.3.0/Gauge.jpg deleted file mode 100644 index aa12a01c9011f187aaf987cf75909c8295a5ba0d..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/Gauge.jpg and /dev/null differ diff --git a/images/v0.3.0/Helloworld.jpg b/images/v0.3.0/Helloworld.jpg deleted file mode 100644 index b3b09009044f89eb47cc853d46c67417ab976b96..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/Helloworld.jpg and /dev/null differ diff --git a/images/v0.3.0/Meter.jpg b/images/v0.3.0/Meter.jpg deleted file mode 100644 index a2c28e14b9d72d42e5bab01ed3a19b4db834d43a..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/Meter.jpg and /dev/null differ diff --git a/images/v0.3.0/Version.jpg b/images/v0.3.0/Version.jpg deleted file mode 100644 index d126d7417318e418dec5f5bde069e7b9afa6ece7..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/Version.jpg and /dev/null differ diff --git a/images/v0.3.0/Watchface.jpg b/images/v0.3.0/Watchface.jpg deleted file mode 100644 index 1cfaa976d200456afb3a1c893d47b9788d6adff1..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/Watchface.jpg and /dev/null differ diff --git a/images/v0.3.0/Watchface2.jpg b/images/v0.3.0/Watchface2.jpg deleted file mode 100644 index 63783051e610f16bff3b0c9d06c35e0dd4f308d1..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/Watchface2.jpg and /dev/null differ diff --git a/images/v0.3.0/menu.jpg b/images/v0.3.0/menu.jpg deleted file mode 100644 index bf94a2e5fc57c6519e7328c3489e0e868e747146..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0/menu.jpg and /dev/null differ diff --git a/images/v0.3.0.png b/images/v0.3.0.png deleted file mode 100644 index 4a2bcdd2ceac191be03becc6ee6ef3d6adff33a7..0000000000000000000000000000000000000000 Binary files a/images/v0.3.0.png and /dev/null differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6971a56246e8dc7151b5cda1450517ed5a90e1e..db4a8e2aae5faea77b122642dee236fc12085006 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -477,7 +477,7 @@ FreeRTOS/port_cmsis_systick.c FreeRTOS/port_cmsis.c displayapp/LittleVgl.cpp - displayapp/lv_pinetime_theme.c + displayapp/InfiniTimeTheme.cpp systemtask/SystemTask.cpp systemtask/SystemMonitor.cpp @@ -663,7 +663,7 @@ libs/date/include/date/julian.h libs/date/include/date/ptz.h libs/date/include/date/tz_private.h displayapp/LittleVgl.h - displayapp/lv_pinetime_theme.h + displayapp/InfiniTimeTheme.h systemtask/SystemTask.h systemtask/SystemMonitor.h displayapp/screens/Symbols.h @@ -810,6 +810,7 @@ add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) + add_definitions(-DDRIVER_DISPLAY_MIRROR) else() message(FATAL_ERROR "Invalid TARGET_DEVICE") endif() diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 3b113eada9afaad8897d3809febe38a5862b4a12..478408f64754fbe874af0a048d9bf003d73808a5 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -9,7 +9,7 @@ namespace Controllers { class Settings { public: enum class ClockType : uint8_t { H24, H12 }; - enum class Notification : uint8_t { ON, OFF }; + enum class Notification : uint8_t { On, Off, Sleep }; enum class ChimesOption : uint8_t { None, Hours, HalfHours }; enum class WakeUpMode : uint8_t { SingleTap = 0, @@ -219,7 +219,7 @@ uint32_t stepsGoal = 10000; uint32_t screenTimeOut = 15000; ClockType clockType = ClockType::H24; - Notification notificationStatus = Notification::ON; + Notification notificationStatus = Notification::On; uint8_t clockFace = 0; ChimesOption chimesOption = ChimesOption::None; diff --git a/src/displayapp/InfiniTimeTheme.cpp b/src/displayapp/InfiniTimeTheme.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4290d87fcbab2d54399ea609716b8c9f9f5a077d --- /dev/null +++ b/src/displayapp/InfiniTimeTheme.cpp @@ -0,0 +1,446 @@ +#include "displayapp/InfiniTimeTheme.h" + +static void theme_apply(lv_obj_t* obj, lv_theme_style_t name); + +static lv_theme_t theme; + +static lv_style_t style_bg; +static lv_style_t style_box; +static lv_style_t style_btn; +static lv_style_t style_label_white; +static lv_style_t style_icon; +static lv_style_t style_bar_indic; +static lv_style_t style_slider_knob; +static lv_style_t style_scrollbar; +static lv_style_t style_list_btn; +static lv_style_t style_ddlist_list; +static lv_style_t style_ddlist_selected; +static lv_style_t style_sw_bg; +static lv_style_t style_sw_indic; +static lv_style_t style_sw_knob; +static lv_style_t style_arc_bg; +static lv_style_t style_arc_knob; +static lv_style_t style_arc_indic; +static lv_style_t style_table_cell; +static lv_style_t style_pad_small; +static lv_style_t style_lmeter; +static lv_style_t style_chart_serie; +static lv_style_t style_cb_bg; +static lv_style_t style_cb_bullet; + +static bool inited; + +static void style_init_reset(lv_style_t* style) { + if (inited) { + lv_style_reset(style); + } else { + lv_style_init(style); + } +} + +static void basic_init() { + style_init_reset(&style_bg); + lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal); + + style_init_reset(&style_box); + lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10); + lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal); + + style_init_reset(&style_label_white); + lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_text_color(&style_label_white, LV_STATE_DISABLED, LV_COLOR_GRAY); + + style_init_reset(&style_btn); + lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10); + lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, Colors::highlight); + lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, Colors::bgDark); + lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0); + + lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); + + lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); + + lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15)); + lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2)); + lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0); + lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0); + lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0); + + style_init_reset(&style_icon); + lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_COLOR_WHITE); + + style_init_reset(&style_bar_indic); + lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10); + + style_init_reset(&style_scrollbar); + lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_size(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 80); + lv_style_set_pad_right(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 60); + + style_init_reset(&style_list_btn); + lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25); + lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25); + lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100); + lv_style_set_pad_bottom(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100); + lv_style_set_pad_inner(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 50); + + style_init_reset(&style_ddlist_list); + // Causes lag unfortunately, so we'll have to live with the selected item overflowing the corner + // lv_style_set_clip_corner(&style_ddlist_list, LV_STATE_DEFAULT, true); + lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25); + lv_style_set_bg_color(&style_ddlist_list, LV_STATE_DEFAULT, Colors::lightGray); + lv_style_set_pad_all(&style_ddlist_list, LV_STATE_DEFAULT, 20); + + style_init_reset(&style_ddlist_selected); + lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, Colors::bg); + + style_init_reset(&style_sw_bg); + lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + + style_init_reset(&style_sw_indic); + lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, Colors::highlight); + + style_init_reset(&style_sw_knob); + lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_COLOR_SILVER); + lv_style_set_bg_color(&style_sw_knob, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, -4); + lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, -4); + lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, -4); + lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, -4); + + style_init_reset(&style_slider_knob); + lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6); + lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10); + lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10); + lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10); + lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10); + lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14); + lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14); + lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14); + lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14); + + style_init_reset(&style_arc_indic); + lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, Colors::lightGray); + lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true); + + style_init_reset(&style_arc_bg); + lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true); + lv_style_set_pad_all(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(5)); + + lv_style_reset(&style_arc_knob); + lv_style_set_radius(&style_arc_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_bg_opa(&style_arc_knob, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_style_set_bg_color(&style_arc_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_pad_all(&style_arc_knob, LV_STATE_DEFAULT, LV_DPX(5)); + + style_init_reset(&style_table_cell); + lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1); + lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL); + lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5); + lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5); + lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2); + lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2); + + style_init_reset(&style_pad_small); + lv_style_int_t pad_small_value = 10; + lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + + style_init_reset(&style_lmeter); + lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30)); + lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25)); + + lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7)); + + style_init_reset(&style_chart_serie); + lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4); + lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4); + lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0); + + lv_style_reset(&style_cb_bg); + lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, 18); + lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2)); + lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0); + lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); + + lv_style_reset(&style_cb_bullet); + lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_pattern_image(&style_cb_bullet, LV_STATE_CHECKED, LV_SYMBOL_OK); + lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); +} + +/** + * Initialize the default + * @param color_primary the primary color of the theme + * @param color_secondary the secondary color for the theme + * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` + * @param font_small pointer to a small font + * @param font_normal pointer to a normal font + * @param font_subtitle pointer to a large font + * @param font_title pointer to a extra large font + * @return a pointer to reference this theme later + */ +lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, + lv_color_t color_secondary, + uint32_t flags, + const lv_font_t* font_small, + const lv_font_t* font_normal, + const lv_font_t* font_subtitle, + const lv_font_t* font_title) { + theme.color_primary = color_primary; + theme.color_secondary = color_secondary; + theme.font_small = font_small; + theme.font_normal = font_normal; + theme.font_subtitle = font_subtitle; + theme.font_title = font_title; + theme.flags = flags; + + basic_init(); + + theme.apply_xcb = theme_apply; + + inited = true; + + return &theme; +} + +static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) { + lv_style_list_t* list; + + switch (name) { + case LV_THEME_NONE: + break; + + case LV_THEME_SCR: + lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN); + _lv_style_list_add_style(list, &style_bg); + _lv_style_list_add_style(list, &style_label_white); + break; + + case LV_THEME_OBJ: + lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN); + _lv_style_list_add_style(list, &style_box); + break; + + case LV_THEME_CONT: + lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN); + _lv_style_list_add_style(list, &style_box); + break; + + case LV_THEME_BTN: + lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); + _lv_style_list_add_style(list, &style_btn); + break; + + case LV_THEME_BTNMATRIX: + list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG); + _lv_style_list_add_style(list, &style_bg); + _lv_style_list_add_style(list, &style_pad_small); + + list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN); + _lv_style_list_add_style(list, &style_btn); + break; + + case LV_THEME_BAR: + lv_obj_clean_style_list(obj, LV_BAR_PART_BG); + list = lv_obj_get_style_list(obj, LV_BAR_PART_BG); + + lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC); + list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC); + _lv_style_list_add_style(list, &style_bar_indic); + break; + + case LV_THEME_IMAGE: + lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN); + _lv_style_list_add_style(list, &style_icon); + break; + + case LV_THEME_LABEL: + lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN); + _lv_style_list_add_style(list, &style_label_white); + break; + + case LV_THEME_SLIDER: + lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG); + list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG); + _lv_style_list_add_style(list, &style_sw_bg); + + lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC); + list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC); + + lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB); + list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB); + _lv_style_list_add_style(list, &style_slider_knob); + break; + + case LV_THEME_LIST: + lv_obj_clean_style_list(obj, LV_LIST_PART_BG); + list = lv_obj_get_style_list(obj, LV_LIST_PART_BG); + _lv_style_list_add_style(list, &style_box); + + lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE); + list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE); + + lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR); + list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR); + _lv_style_list_add_style(list, &style_scrollbar); + break; + + case LV_THEME_LIST_BTN: + lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); + _lv_style_list_add_style(list, &style_list_btn); + break; + + case LV_THEME_ARC: + lv_obj_clean_style_list(obj, LV_ARC_PART_BG); + list = lv_obj_get_style_list(obj, LV_ARC_PART_BG); + _lv_style_list_add_style(list, &style_arc_bg); + + lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC); + list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC); + _lv_style_list_add_style(list, &style_arc_indic); + + lv_obj_clean_style_list(obj, LV_ARC_PART_KNOB); + list = lv_obj_get_style_list(obj, LV_ARC_PART_KNOB); + _lv_style_list_add_style(list, &style_arc_knob); + break; + + case LV_THEME_SWITCH: + lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG); + list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG); + _lv_style_list_add_style(list, &style_sw_bg); + + lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC); + list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC); + _lv_style_list_add_style(list, &style_sw_indic); + + lv_obj_clean_style_list(obj, LV_SWITCH_PART_KNOB); + list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB); + _lv_style_list_add_style(list, &style_sw_knob); + break; + + case LV_THEME_DROPDOWN: + lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN); + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN); + _lv_style_list_add_style(list, &style_btn); + + lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST); + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST); + _lv_style_list_add_style(list, &style_box); + _lv_style_list_add_style(list, &style_ddlist_list); + + lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED); + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED); + _lv_style_list_add_style(list, &style_ddlist_selected); + + lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR); + list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR); + _lv_style_list_add_style(list, &style_scrollbar); + break; + + case LV_THEME_TABLE: { + list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG); + _lv_style_list_add_style(list, &style_bg); + + int idx = 1; /* start value should be 1, not zero, since cell styles + start at 1 due to presence of LV_TABLE_PART_BG=0 + in the enum (lv_table.h) */ + /* declaring idx outside loop to work with older compilers */ + for (; idx <= LV_TABLE_CELL_STYLE_CNT; idx++) { + list = lv_obj_get_style_list(obj, idx); + _lv_style_list_add_style(list, &style_table_cell); + _lv_style_list_add_style(list, &style_label_white); + } + } break; + + case LV_THEME_LINEMETER: + list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN); + _lv_style_list_add_style(list, &style_bg); + _lv_style_list_add_style(list, &style_lmeter); + break; + + case LV_THEME_CHART: + lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES); + list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES); + _lv_style_list_add_style(list, &style_btn); + _lv_style_list_add_style(list, &style_chart_serie); + break; + + case LV_THEME_CHECKBOX: + list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG); + _lv_style_list_add_style(list, &style_cb_bg); + + list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET); + _lv_style_list_add_style(list, &style_btn); + _lv_style_list_add_style(list, &style_cb_bullet); + break; + + default: + break; + } + + lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); +} diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h new file mode 100644 index 0000000000000000000000000000000000000000..5709b0071b5f68d9b89c7722598c356a1cf3d30b --- /dev/null +++ b/src/displayapp/InfiniTimeTheme.h @@ -0,0 +1,33 @@ +#pragma once + +#include <lvgl/lvgl.h> + +namespace Colors { + static constexpr lv_color_t orange = LV_COLOR_MAKE(0xff, 0xb0, 0x0); + static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0); + static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0); + + static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); + static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38); + static constexpr lv_color_t bgDark = LV_COLOR_MAKE(0x18, 0x18, 0x18); + static constexpr lv_color_t highlight = green; +}; + +/** + * Initialize the default + * @param color_primary the primary color of the theme + * @param color_secondary the secondary color for the theme + * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` + * @param font_small pointer to a small font + * @param font_normal pointer to a normal font + * @param font_subtitle pointer to a large font + * @param font_title pointer to a extra large font + * @return a pointer to reference this theme later + */ +lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, + lv_color_t color_secondary, + uint32_t flags, + const lv_font_t* font_small, + const lv_font_t* font_normal, + const lv_font_t* font_subtitle, + const lv_font_t* font_title); diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index 64c99261764eb100eed7e6a0d1f6a1c31e1af350..d5f31848c46cb2f72ad123f0e42d3f7702a67329 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -1,5 +1,5 @@ #include "displayapp/LittleVgl.h" -#include "displayapp/lv_pinetime_theme.h" +#include "displayapp/InfiniTimeTheme.h" #include <FreeRTOS.h> #include <task.h> diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index 9d5ec2821f44b0dfed3696fc6123e1459e36461a..b2669a788cc035ffd63bd80315765b4887f05c2b 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -1,19 +1,19 @@ # Fonts -* [Jetbrains Mono](https://www.jetbrains.com/lp/mono/) -* [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid) -* [Open Sans Light](https://fonts.google.com/specimen/Open+Sans) -* [Material Symbols](https://fonts.google.com/icons) +- [Jetbrains Mono](https://www.jetbrains.com/lp/mono/) +- [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid) +- [Open Sans Light](https://fonts.google.com/specimen/Open+Sans) +- [Material Symbols](https://fonts.google.com/icons) ### How to add new symbols: -* Browse the cheat sheets and pick symbols - * [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid) - * [Material Symbols](https://fonts.google.com/icons) -* For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list in the `fonts.json` file -* Convert this hex value into a UTF-8 code +- Browse the cheat sheets and pick symbols + - [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid) + - [Material Symbols](https://fonts.google.com/icons) +- For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list in the `fonts.json` file +- Convert this hex value into a UTF-8 code using [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f185&mode=hex) -* Define the new symbols in `src/displayapp/screens/Symbols.h`: +- Define the new symbols in `src/displayapp/screens/Symbols.h`: ``` static constexpr const char* newSymbol = "\xEF\x86\x85"; @@ -23,13 +23,13 @@ ### the config file format: inside `fonts`, there is a dictionary of fonts, and for each font there is: -* sources - list of file,range(,symbols) wanted (as a dictionary of those) -* bpp - bits per pixel. -* size - size. -* patches - list of extra "patches" to run: a path to a .patch file. (may be relative) -* compress - optional. default disabled. add `"compress": true` to enable + +- sources - list of file,range(,symbols) wanted (as a dictionary of those) +- bpp - bits per pixel. +- size - size. +- patches - list of extra "patches" to run: a path to a .patch file. (may be relative) +- compress - optional. default disabled. add `"compress": true` to enable ### Navigation font `navigtion.ttf` is created with the web app [icomoon](https://icomoon.io/app) by importing the svg files from `src/displayapp/icons/navigation/unique` and generating the font. `lv_font_navi_80.json` is a project file for the site, which you can import to add or remove icons. - diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 9f228fb6aabf5f1bba309c320979fabe8b4a938c..006b884947769ab6e8bd1663bc24e8badf98a2a4 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ "range": "0x20-0x7e, 0x410-0x44f" }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf00c" } ], "bpp": 1, @@ -58,7 +58,7 @@ "lv_font_sys_48": { "sources": [ { "file": "material-design-icons/MaterialIcons-Regular.ttf", - "range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8" + "range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8, 0xef44" } ], "bpp": 1, diff --git a/src/displayapp/lv_pinetime_theme.c b/src/displayapp/lv_pinetime_theme.c deleted file mode 100644 index f712004afdffeb879c283cdec8eb531b5acb197f..0000000000000000000000000000000000000000 --- a/src/displayapp/lv_pinetime_theme.c +++ /dev/null @@ -1,447 +0,0 @@ -#include "displayapp/lv_pinetime_theme.h" - -static void theme_apply(lv_obj_t* obj, lv_theme_style_t name); - -static lv_theme_t theme; - -static lv_style_t style_bg; -static lv_style_t style_box; -static lv_style_t style_btn; -static lv_style_t style_label_white; -static lv_style_t style_icon; -static lv_style_t style_bar_indic; -static lv_style_t style_slider_knob; -static lv_style_t style_scrollbar; -static lv_style_t style_list_btn; -static lv_style_t style_ddlist_list; -static lv_style_t style_ddlist_selected; -static lv_style_t style_sw_bg; -static lv_style_t style_sw_indic; -static lv_style_t style_sw_knob; -static lv_style_t style_arc_bg; -static lv_style_t style_arc_knob; -static lv_style_t style_arc_indic; -static lv_style_t style_table_cell; -static lv_style_t style_pad_small; -static lv_style_t style_lmeter; -static lv_style_t style_chart_serie; -static lv_style_t style_cb_bg; -static lv_style_t style_cb_bullet; - -static bool inited; - -static void style_init_reset(lv_style_t* style) { - if (inited) - lv_style_reset(style); - else - lv_style_init(style); -} - -static void basic_init(void) { - style_init_reset(&style_bg); - lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal); - - style_init_reset(&style_box); - lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10); - lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, IT_COLOR_BG); - lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal); - - style_init_reset(&style_label_white); - lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_text_color(&style_label_white, LV_STATE_DISABLED, LV_COLOR_GRAY); - - style_init_reset(&style_btn); - lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10); - lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, IT_COLOR_BG); - lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, IT_COLOR_SEL); - lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, IT_COLOR_BG_DARK); - lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0); - - lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); - - lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); - - lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15)); - lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0); - lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0); - lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0); - - style_init_reset(&style_icon); - lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_COLOR_WHITE); - - style_init_reset(&style_bar_indic); - lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10); - - style_init_reset(&style_scrollbar); - lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_size(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 80); - lv_style_set_pad_right(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 60); - - style_init_reset(&style_list_btn); - lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, IT_COLOR_BG); - lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, IT_COLOR_BG); - lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25); - lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25); - lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100); - lv_style_set_pad_bottom(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100); - lv_style_set_pad_inner(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 50); - - style_init_reset(&style_ddlist_list); - // Causes lag unfortunately, so we'll have to live with the selected item overflowing the corner - // lv_style_set_clip_corner(&style_ddlist_list, LV_STATE_DEFAULT, true); - lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25); - lv_style_set_bg_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); - lv_style_set_pad_all(&style_ddlist_list, LV_STATE_DEFAULT, 20); - - style_init_reset(&style_ddlist_selected); - lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, IT_COLOR_BG); - - style_init_reset(&style_sw_bg); - lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, IT_COLOR_BG); - lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - - style_init_reset(&style_sw_indic); - lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, IT_COLOR_SEL); - - style_init_reset(&style_sw_knob); - lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_COLOR_SILVER); - lv_style_set_bg_color(&style_sw_knob, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, -4); - - style_init_reset(&style_slider_knob); - lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED); - lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6); - lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14); - - style_init_reset(&style_arc_indic); - lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); - lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25)); - lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true); - - style_init_reset(&style_arc_bg); - lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, IT_COLOR_BG); - lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25)); - lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true); - lv_style_set_pad_all(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(5)); - - lv_style_reset(&style_arc_knob); - lv_style_set_radius(&style_arc_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_bg_opa(&style_arc_knob, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_arc_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_pad_all(&style_arc_knob, LV_STATE_DEFAULT, LV_DPX(5)); - - style_init_reset(&style_table_cell); - lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_COLOR_GRAY); - lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1); - lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL); - lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5); - lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5); - lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2); - lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2); - - style_init_reset(&style_pad_small); - lv_style_int_t pad_small_value = 10; - lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - - style_init_reset(&style_lmeter); - lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30)); - lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25)); - - lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_GRAY); - lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10)); - lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7)); - - style_init_reset(&style_chart_serie); - lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4); - lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4); - lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0); - - lv_style_reset(&style_cb_bg); - lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); - lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, 18); - lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0); - lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); - - lv_style_reset(&style_cb_bullet); - lv_style_set_outline_opa(&style_cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP); - lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4)); - lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); -} - -/** - * Initialize the default - * @param color_primary the primary color of the theme - * @param color_secondary the secondary color for the theme - * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` - * @param font_small pointer to a small font - * @param font_normal pointer to a normal font - * @param font_subtitle pointer to a large font - * @param font_title pointer to a extra large font - * @return a pointer to reference this theme later - */ -lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, - lv_color_t color_secondary, - uint32_t flags, - const lv_font_t* font_small, - const lv_font_t* font_normal, - const lv_font_t* font_subtitle, - const lv_font_t* font_title) { - theme.color_primary = color_primary; - theme.color_secondary = color_secondary; - theme.font_small = font_small; - theme.font_normal = font_normal; - theme.font_subtitle = font_subtitle; - theme.font_title = font_title; - theme.flags = flags; - - basic_init(); - - theme.apply_xcb = theme_apply; - - inited = true; - - return &theme; -} - -static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) { - lv_style_list_t* list; - - /*To avoid warnings*/ - uint32_t name_int = (uint32_t) name; - switch (name_int) { - case LV_THEME_NONE: - break; - - case LV_THEME_SCR: - lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN); - _lv_style_list_add_style(list, &style_bg); - _lv_style_list_add_style(list, &style_label_white); - break; - - case LV_THEME_OBJ: - lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN); - _lv_style_list_add_style(list, &style_box); - break; - - case LV_THEME_CONT: - lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN); - _lv_style_list_add_style(list, &style_box); - break; - - case LV_THEME_BTN: - lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); - _lv_style_list_add_style(list, &style_btn); - break; - - case LV_THEME_BTNMATRIX: - list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG); - _lv_style_list_add_style(list, &style_bg); - _lv_style_list_add_style(list, &style_pad_small); - - list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN); - _lv_style_list_add_style(list, &style_btn); - break; - - case LV_THEME_BAR: - lv_obj_clean_style_list(obj, LV_BAR_PART_BG); - list = lv_obj_get_style_list(obj, LV_BAR_PART_BG); - - lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC); - list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC); - _lv_style_list_add_style(list, &style_bar_indic); - break; - - case LV_THEME_IMAGE: - lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN); - _lv_style_list_add_style(list, &style_icon); - break; - - case LV_THEME_LABEL: - lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN); - _lv_style_list_add_style(list, &style_label_white); - break; - - case LV_THEME_SLIDER: - lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG); - list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG); - _lv_style_list_add_style(list, &style_sw_bg); - - lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC); - list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC); - - lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB); - list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB); - _lv_style_list_add_style(list, &style_slider_knob); - break; - - case LV_THEME_LIST: - lv_obj_clean_style_list(obj, LV_LIST_PART_BG); - list = lv_obj_get_style_list(obj, LV_LIST_PART_BG); - _lv_style_list_add_style(list, &style_box); - - lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE); - list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE); - - lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR); - list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR); - _lv_style_list_add_style(list, &style_scrollbar); - break; - - case LV_THEME_LIST_BTN: - lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN); - _lv_style_list_add_style(list, &style_list_btn); - break; - - case LV_THEME_ARC: - lv_obj_clean_style_list(obj, LV_ARC_PART_BG); - list = lv_obj_get_style_list(obj, LV_ARC_PART_BG); - _lv_style_list_add_style(list, &style_arc_bg); - - lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC); - list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC); - _lv_style_list_add_style(list, &style_arc_indic); - - lv_obj_clean_style_list(obj, LV_ARC_PART_KNOB); - list = lv_obj_get_style_list(obj, LV_ARC_PART_KNOB); - _lv_style_list_add_style(list, &style_arc_knob); - break; - - case LV_THEME_SWITCH: - lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG); - list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG); - _lv_style_list_add_style(list, &style_sw_bg); - - lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC); - list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC); - _lv_style_list_add_style(list, &style_sw_indic); - - lv_obj_clean_style_list(obj, LV_SWITCH_PART_KNOB); - list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB); - _lv_style_list_add_style(list, &style_sw_knob); - break; - - case LV_THEME_DROPDOWN: - lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN); - list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN); - _lv_style_list_add_style(list, &style_btn); - - lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST); - list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST); - _lv_style_list_add_style(list, &style_box); - _lv_style_list_add_style(list, &style_ddlist_list); - - lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED); - list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED); - _lv_style_list_add_style(list, &style_ddlist_selected); - - lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR); - list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR); - _lv_style_list_add_style(list, &style_scrollbar); - break; - - case LV_THEME_TABLE: - list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG); - _lv_style_list_add_style(list, &style_bg); - - int idx = 1; /* start value should be 1, not zero, since cell styles - start at 1 due to presence of LV_TABLE_PART_BG=0 - in the enum (lv_table.h) */ - /* declaring idx outside loop to work with older compilers */ - for (; idx <= LV_TABLE_CELL_STYLE_CNT; idx++) { - list = lv_obj_get_style_list(obj, idx); - _lv_style_list_add_style(list, &style_table_cell); - _lv_style_list_add_style(list, &style_label_white); - } - break; - - case LV_THEME_LINEMETER: - list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN); - _lv_style_list_add_style(list, &style_bg); - _lv_style_list_add_style(list, &style_lmeter); - break; - - case LV_THEME_CHART: - lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES); - list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES); - _lv_style_list_add_style(list, &style_btn); - _lv_style_list_add_style(list, &style_chart_serie); - break; - - case LV_THEME_CHECKBOX: - list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG); - _lv_style_list_add_style(list, &style_cb_bg); - - list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET); - _lv_style_list_add_style(list, &style_btn); - _lv_style_list_add_style(list, &style_cb_bullet); - break; - - default: - break; - } - - lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); -} diff --git a/src/displayapp/lv_pinetime_theme.h b/src/displayapp/lv_pinetime_theme.h deleted file mode 100644 index b68b7380cf3c810ef775746560a1052fad7e4b9b..0000000000000000000000000000000000000000 --- a/src/displayapp/lv_pinetime_theme.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include <lvgl/lvgl.h> - -#define IT_COLOR_BG LV_COLOR_MAKE(0x5d, 0x69, 0x7e) -#define IT_COLOR_BG_DARK LV_COLOR_MAKE(0x18, 0x18, 0x18) -#define IT_COLOR_SEL LV_COLOR_MAKE(0x0, 0xb0, 0x0) - -/** - * Initialize the default - * @param color_primary the primary color of the theme - * @param color_secondary the secondary color for the theme - * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` - * @param font_small pointer to a small font - * @param font_normal pointer to a normal font - * @param font_subtitle pointer to a large font - * @param font_title pointer to a extra large font - * @return a pointer to reference this theme later - */ -lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, - lv_color_t color_secondary, - uint32_t flags, - const lv_font_t* font_small, - const lv_font_t* font_normal, - const lv_font_t* font_subtitle, - const lv_font_t* font_title); -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index 427650c6ef76265003070260042d0579862264e7..d6371ce66fe55579b0286e56f3be5e061fce6646 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -18,6 +18,7 @@ */ #include "displayapp/screens/Alarm.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; using Pinetime::Controllers::AlarmController; @@ -79,7 +80,7 @@ txtStop = lv_label_create(btnStop, nullptr); lv_label_set_text_static(txtStop, Symbols::stop); lv_obj_set_hidden(btnStop, true); - static constexpr lv_color_t bgColor = LV_COLOR_MAKE(0x38, 0x38, 0x38); + static constexpr lv_color_t bgColor = Colors::bgAlt; btnRecur = lv_btn_create(lv_scr_act(), nullptr); btnRecur->user_data = this; diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index d9d479f8b14768bf7155462de937ba20652030ef..9febda61a9454922f9fe32360480b1648f8559d0 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/BatteryInfo.h" #include "displayapp/DisplayApp.h" #include "components/battery/BatteryController.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -16,9 +17,9 @@ lv_bar_set_range(charging_bar, 0, 100); lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10); lv_bar_set_anim_time(charging_bar, 1000); lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222)); + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON); status = lv_label_create(lv_scr_act(), nullptr); @@ -33,7 +34,7 @@ lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT); lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60); voltage = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0)); + lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10); lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER); lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95); @@ -62,7 +63,7 @@ } else if (batteryPercent < 10) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_label_set_text_static(status, "Battery low"); } else { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::highlight); lv_label_set_text_static(status, "Discharging"); } diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp index a3c9761633087806bcb3fbfb0f289e3deb37be4a..a2314690c35479ee15ab223abce16403f8c3e71c 100644 --- a/src/displayapp/screens/FirmwareValidation.cpp +++ b/src/displayapp/screens/FirmwareValidation.cpp @@ -3,6 +3,7 @@ #include #include "Version.h" #include "components/firmwarevalidator/FirmwareValidator.h" #include "displayapp/DisplayApp.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -42,7 +43,7 @@ buttonValidate->user_data = this; lv_obj_set_size(buttonValidate, 115, 50); lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_set_event_cb(buttonValidate, ButtonEventHandler); - lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); labelButtonValidate = lv_label_create(buttonValidate, nullptr); lv_label_set_text_static(labelButtonValidate, "Validate"); @@ -51,7 +52,7 @@ buttonReset = lv_btn_create(lv_scr_act(), nullptr); buttonReset->user_data = this; lv_obj_set_size(buttonReset, 115, 50); lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0x0, 0x0)); + lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); lv_obj_set_event_cb(buttonReset, ButtonEventHandler); labelButtonReset = lv_label_create(buttonReset, nullptr); diff --git a/src/displayapp/screens/FlashLight.cpp b/src/displayapp/screens/FlashLight.cpp index b00bb0fa73abc020a8f5400a846060d6866a794b..e06b59b5b4d35ef8d83ee9d9d138299097eaaaf3 100644 --- a/src/displayapp/screens/FlashLight.cpp +++ b/src/displayapp/screens/FlashLight.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/FlashLight.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -58,7 +59,7 @@ } void FlashLight::SetColors() { lv_color_t bgColor = isOn ? LV_COLOR_WHITE : LV_COLOR_BLACK; - lv_color_t fgColor = isOn ? LV_COLOR_MAKE(0xb0, 0xb0, 0xb0) : LV_COLOR_WHITE; + lv_color_t fgColor = isOn ? Colors::lightGray : LV_COLOR_WHITE; lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, bgColor); lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fgColor); diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp index 35e06bbccba55aee32167cfc52369535d5875714..305e0c4bd92b11d1166f1ff01111532b54a07f1b 100644 --- a/src/displayapp/screens/HeartRate.cpp +++ b/src/displayapp/screens/HeartRate.cpp @@ -3,6 +3,7 @@ #include #include <components/heartrate/HeartRateController.h> #include "displayapp/DisplayApp.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -36,10 +37,11 @@ label_hr = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - if (isHrRunning) - lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); - else - lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + if (isHrRunning) { + lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); + } else { + lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + } lv_label_set_text_static(label_hr, "000"); lv_obj_align(label_hr, nullptr, LV_ALIGN_CENTER, 0, -40); @@ -97,12 +99,12 @@ if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) { heartRateController.Start(); UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped); systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); - lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); } else { heartRateController.Stop(); UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped); systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); - lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); } } } diff --git a/src/displayapp/screens/InfiniPaint.cpp b/src/displayapp/screens/InfiniPaint.cpp index 733b4e270d111177f6bdd4e21e9bc3f50a55770e..0b6864e8925f71bd36796ff4515ea9dd2672efe0 100644 --- a/src/displayapp/screens/InfiniPaint.cpp +++ b/src/displayapp/screens/InfiniPaint.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/InfiniPaint.h" #include "displayapp/DisplayApp.h" #include "displayapp/LittleVgl.h" +#include "displayapp/InfiniTimeTheme.h" #include <algorithm> // std::fill @@ -26,7 +27,7 @@ case 0: selectColor = LV_COLOR_MAGENTA; break; case 1: - selectColor = LV_COLOR_MAKE(0x0, 0xb0, 0x0); + selectColor = Colors::green; break; case 2: selectColor = LV_COLOR_WHITE; diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp index 2ffc52dde3ab5b969829e43099e1740f66d3efc2..174ac1b652a59a8746ce28575a44fbb221fe91ec 100644 --- a/src/displayapp/screens/Metronome.cpp +++ b/src/displayapp/screens/Metronome.cpp @@ -1,5 +1,6 @@ #include "displayapp/screens/Metronome.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -12,7 +13,7 @@ lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x, uint8_t y) { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font); - lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_label_set_text(label, name); lv_obj_align(label, reference, align, x, y); diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp index f7ffcc7c0f470ebd380b04f0b077201c80827234..c2dc4dac1ab6a9fc32272e09871ba3ad3dfc7074 100644 --- a/src/displayapp/screens/Motion.cpp +++ b/src/displayapp/screens/Motion.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/Motion.h" #include <lvgl/lvgl.h> #include "displayapp/DisplayApp.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -19,7 +20,7 @@ lv_chart_set_point_count(chart, 10); /*Add 3 data series*/ ser1 = lv_chart_add_series(chart, LV_COLOR_RED); - ser2 = lv_chart_add_series(chart, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + ser2 = lv_chart_add_series(chart, Colors::green); ser3 = lv_chart_add_series(chart, LV_COLOR_YELLOW); lv_chart_init_points(chart, ser1, 0); diff --git a/src/displayapp/screens/Navigation.cpp b/src/displayapp/screens/Navigation.cpp index 5779df3a267b5d1aa65b2f7e57b876a50537859b..f6389734e1643aaee20795208f612aa61ee78ddb 100644 --- a/src/displayapp/screens/Navigation.cpp +++ b/src/displayapp/screens/Navigation.cpp @@ -19,6 +19,7 @@ #include "displayapp/screens/Navigation.h" #include <cstdint> #include "displayapp/DisplayApp.h" #include "components/ble/NavigationService.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -192,7 +193,7 @@ lv_bar_set_value(barProgress, progress, LV_ANIM_OFF); if (progress > 90) { lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); } else { - lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0)); + lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::orange); } } } diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 768ac2909c2486b559b6cb9ffcb9daf2ef4ed1bc..90a010f5fc391b6ed6aa4e7d5948976f7f00324e 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -4,6 +4,7 @@ #include "components/ble/MusicService.h" #include "components/ble/AlertNotificationService.h" #include "displayapp/screens/Symbols.h" #include <algorithm> +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; extern lv_font_t jetbrains_mono_extrabold_compressed; @@ -257,7 +258,7 @@ lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_border_width(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); subject_container = lv_cont_create(container, nullptr); - lv_obj_set_style_local_bg_color(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38)); + lv_obj_set_style_local_bg_color(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_pad_all(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); lv_obj_set_style_local_pad_inner(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); lv_obj_set_style_local_border_width(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); @@ -272,7 +273,7 @@ lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb); lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16); lv_obj_t* alert_type = lv_label_create(container, nullptr); - lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0)); + lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); if (title == nullptr) { lv_label_set_text_static(alert_type, "Notification"); } else { @@ -314,7 +315,7 @@ lv_obj_set_size(bt_accept, 76, 76); lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); label_accept = lv_label_create(bt_accept, nullptr); lv_label_set_text_static(label_accept, Symbols::phone); - lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); bt_reject = lv_btn_create(container, nullptr); bt_reject->user_data = this; @@ -332,7 +333,7 @@ lv_obj_set_size(bt_mute, 76, 76); lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); label_mute = lv_label_create(bt_mute, nullptr); lv_label_set_text_static(label_mute, Symbols::volumMute); - lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); } break; } } diff --git a/src/displayapp/screens/PassKey.cpp b/src/displayapp/screens/PassKey.cpp index 4057a7eb8859fa67e390b457797121f834b1e81b..5d255e444c62d04907f266c49a040cb87bc5deb6 100644 --- a/src/displayapp/screens/PassKey.cpp +++ b/src/displayapp/screens/PassKey.cpp @@ -5,7 +5,7 @@ using namespace Pinetime::Applications::Screens; PassKey::PassKey(Pinetime::Applications::DisplayApp* app, uint32_t key) : Screen(app) { passkeyLabel = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(passkeyLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFF00)); + lv_obj_set_style_local_text_color(passkeyLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_obj_set_style_local_text_font(passkeyLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_fmt(passkeyLabel, "%06u", key); lv_obj_align(passkeyLabel, nullptr, LV_ALIGN_CENTER, 0, -20); diff --git a/src/displayapp/screens/Steps.cpp b/src/displayapp/screens/Steps.cpp index 0dcdcf596d0a61447fa48f3d7b2dd5cd8bc2c5df..10ccf1aa2136688ef3a9d650582361373ea25005 100644 --- a/src/displayapp/screens/Steps.cpp +++ b/src/displayapp/screens/Steps.cpp @@ -20,7 +20,7 @@ lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0); lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2); lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); - lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0x0000FF)); + lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_arc_set_end_angle(stepsArc, 200); lv_obj_set_size(stepsArc, 240, 240); lv_arc_set_range(stepsArc, 0, 500); @@ -32,7 +32,7 @@ lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal())); lSteps = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00)); + lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); lv_obj_set_style_local_text_font(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_fmt(lSteps, "%li", stepsCount); lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -40); diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index e705fcb0bf9748eda587d6a2ddecc0b378479c59..c68cd854125220202359d6927f6f1aca73ac7ed9 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/StopWatch.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -30,13 +31,13 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) : Screen(app), systemTask {systemTask} { 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_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_label_set_text_static(time, "00:00"); lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45); msecTime = lv_label_create(lv_scr_act(), nullptr); // lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_label_set_text_static(msecTime, "00"); lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3); @@ -75,8 +76,8 @@ void StopWatch::Reset() { currentState = States::Init; oldTimeElapsed = 0; - lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_label_set_text_static(time, "00:00"); lv_label_set_text_static(msecTime, "00"); @@ -90,8 +91,8 @@ void StopWatch::Start() { lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); - lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); + lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); lv_label_set_text_static(txtPlayPause, Symbols::pause); lv_label_set_text_static(txtStopLap, Symbols::lapsFlag); startTime = xTaskGetTickCount(); diff --git a/src/displayapp/screens/Styles.cpp b/src/displayapp/screens/Styles.cpp index bcfd584f47e2cc63fd7be3ac25c45580ed51dac6..cebdc70cc69d5c334dc1c363068ff268fce47e23 100644 --- a/src/displayapp/screens/Styles.cpp +++ b/src/displayapp/screens/Styles.cpp @@ -1,8 +1,9 @@ #include "Styles.h" +#include "displayapp/InfiniTimeTheme.h" void Pinetime::Applications::Screens::SetRadioButtonStyle(lv_obj_t* checkbox) { lv_obj_set_style_local_radius(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_style_local_border_width(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, 9); - lv_obj_set_style_local_border_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_border_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, Colors::highlight); lv_obj_set_style_local_bg_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, LV_COLOR_WHITE); } diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index c6e76e360df20a845db5ddb206739766641b7015..1180ec6f2825e3999922fde4dff620d112fbd18c 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -37,6 +37,7 @@ static constexpr const char* drum = "\xEF\x95\xA9"; static constexpr const char* chartLine = "\xEF\x88\x81"; static constexpr const char* eye = "\xEF\x81\xAE"; static constexpr const char* home = "\xEF\x80\x95"; + static constexpr const char* sleep = "\xEE\xBD\x84"; // lv_font_sys_48.c static constexpr const char* settings = "\xEE\xA2\xB8"; diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index 540597969fa84b27b3830187176c3cc1c08af345..01c351955ec4fd772e1f48c4868b1dabfd611860 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -12,6 +12,7 @@ #include "components/brightness/BrightnessController.h" #include "components/datetime/DateTimeController.h" #include "components/motion/MotionController.h" #include "drivers/Watchdog.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -218,7 +219,7 @@ lv_obj_t* infoTask = lv_table_create(lv_scr_act(), nullptr); lv_table_set_col_cnt(infoTask, 4); lv_table_set_row_cnt(infoTask, maxTaskCount + 1); lv_obj_set_style_local_pad_all(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 0); - lv_obj_set_style_local_border_color(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_border_color(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, Colors::lightGray); lv_table_set_cell_value(infoTask, 0, 0, "#"); lv_table_set_col_width(infoTask, 0, 30); diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index bf0780f18e0fb94c8fbbe15e870c43424bffe05a..a60076ed635e0f9cb03f49cd523362f647341848 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -2,6 +2,7 @@ #include "displayapp/screens/Tile.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/BatteryIcon.h" #include "components/ble/BleController.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -71,7 +72,7 @@ lv_obj_set_style_local_radius(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, 20); lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_OPA_50); lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_COLOR_AQUA); lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, LV_OPA_50); - lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, lv_color_hex(0x111111)); + lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, Colors::bgDark); lv_obj_set_style_local_pad_all(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_pad_inner(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 10); diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index a25be1c4ffbe5bfaefa38d571f6ca82e23c9839b..136d6b52afac0695d57182ddea85c9f7af159eb3 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/Timer.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" #include <lvgl/lvgl.h> using namespace Pinetime::Applications::Screens; @@ -54,7 +55,7 @@ btnPlayPause = lv_btn_create(btnObjectMask, nullptr); btnPlayPause->user_data = this; lv_obj_set_style_local_radius(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38)); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_event_cb(btnPlayPause, btnEventHandler); lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50); diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 251a560f6eeac5db579be4781c3f756c8f8b13ae..5ebb330423d1180d46387e64f2c34f079fc5d8df 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -6,6 +6,7 @@ #include "displayapp/screens/BleIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/NotificationIcon.h" #include "components/settings/Settings.h" +#include "displayapp/InfiniTimeTheme.h" LV_IMG_DECLARE(bg_clock); @@ -73,14 +74,14 @@ lv_obj_set_style_local_text_color(plugIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); 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)); + lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); // Date - Day / Week day label_date_day = lv_label_create(lv_scr_act(), NULL); - lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0)); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER); lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0); diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 7e876d8f6e973351722fe164d59711cfe302504e..705272f7cb09b907fd6f616362f02ed4cbb19fb1 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -34,7 +34,7 @@ statusIcons.Create(); notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00)); + lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.cpp b/src/displayapp/screens/WatchFacePineTimeStyle.cpp index 63b421da10a269e1b3e13241871d6cd969ed52f9..ed09f5dd5fcc45ba61c5f2f1ceee95f221ca3e0d 100644 --- a/src/displayapp/screens/WatchFacePineTimeStyle.cpp +++ b/src/displayapp/screens/WatchFacePineTimeStyle.cpp @@ -104,11 +104,11 @@ lv_obj_set_style_local_text_color(plugIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_align(plugIcon, 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_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_label_set_text_static(bleIcon, ""); notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); + lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_label_set_text_static(notificationIcon, ""); // Calendar icon diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index f756006617582656f502fdcec964e7be11bbc5ac..b76affc97670b7295c94ab8f8ea54e017da1e6d0 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -2,20 +2,29 @@ #include "displayapp/screens/settings/QuickSettings.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/BatteryIcon.h" -#include <components/ble/BleController.h> +#include "components/ble/BleController.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; namespace { void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast<QuickSettings*>(obj->user_data); - screen->OnButtonEvent(obj, event); + if (event == LV_EVENT_CLICKED) { + screen->OnButtonEvent(obj); + } } void lv_update_task(struct _lv_task_t* task) { auto* user_data = static_cast<QuickSettings*>(task->user_data); user_data->UpdateScreen(); } + + enum class ButtonState : lv_state_t { + NotificationsOn = LV_STATE_CHECKED, + NotificationsOff = LV_STATE_DEFAULT, + Sleep = 0x40, + }; } QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, @@ -50,7 +59,7 @@ static constexpr uint8_t buttonXOffset = (LV_HOR_RES_MAX - buttonWidth * 2 - innerDistance) / 2; lv_style_init(&btn_style); lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, buttonHeight / 4); - lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38)); + lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt); btn1 = lv_btn_create(lv_scr_act(), nullptr); btn1->user_data = this; @@ -78,19 +87,24 @@ btn3 = lv_btn_create(lv_scr_act(), nullptr); btn3->user_data = this; lv_obj_set_event_cb(btn3, ButtonEventHandler); - lv_btn_set_checkable(btn3, true); lv_obj_add_style(btn3, LV_BTN_PART_MAIN, &btn_style); + lv_obj_set_style_local_bg_color(btn3, LV_BTN_PART_MAIN, static_cast<lv_state_t>(ButtonState::NotificationsOff), LV_COLOR_RED); + static constexpr lv_color_t violet = LV_COLOR_MAKE(0x60, 0x00, 0xff); + lv_obj_set_style_local_bg_color(btn3, LV_BTN_PART_MAIN, static_cast<lv_state_t>(ButtonState::Sleep), violet); lv_obj_set_size(btn3, buttonWidth, buttonHeight); lv_obj_align(btn3, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, buttonXOffset, 0); 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.GetNotificationStatus() == Controllers::Settings::Notification::ON) { - lv_obj_add_state(btn3, LV_STATE_CHECKED); + if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) { lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn); - } else { + lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOn)); + } else if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::Off) { lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff); + } else { + lv_label_set_text_static(btn3_lvl, Symbols::sleep); + lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::Sleep)); } btn4 = lv_btn_create(lv_scr_act(), nullptr); @@ -121,31 +135,33 @@ lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); statusIcons.Update(); } -void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) { - if (object == btn2 && event == LV_EVENT_CLICKED) { - - running = false; +void QuickSettings::OnButtonEvent(lv_obj_t* object) { + if (object == btn2) { app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::Up); - - } else if (object == btn1 && event == LV_EVENT_CLICKED) { + } else if (object == btn1) { brightness.Step(); lv_label_set_text_static(btn1_lvl, brightness.GetIcon()); settingsController.SetBrightness(brightness.Level()); - } else if (object == btn3 && event == LV_EVENT_VALUE_CHANGED) { + } else if (object == btn3) { - if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) { - settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON); - motorController.RunForDuration(35); - lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn); - } else { - settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF); + if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) { + settingsController.SetNotificationStatus(Controllers::Settings::Notification::Off); lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff); + lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOff)); + } else if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::Off) { + settingsController.SetNotificationStatus(Controllers::Settings::Notification::Sleep); + lv_label_set_text_static(btn3_lvl, Symbols::sleep); + lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::Sleep)); + } else { + settingsController.SetNotificationStatus(Controllers::Settings::Notification::On); + lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn); + lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOn)); + motorController.RunForDuration(35); } - } else if (object == btn4 && event == LV_EVENT_CLICKED) { - running = false; + } else if (object == btn4) { settingsController.SetSettingsMenu(0); app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up); } diff --git a/src/displayapp/screens/settings/QuickSettings.h b/src/displayapp/screens/settings/QuickSettings.h index cd342b0c75e74f13dbb9413479f46a12c4f30562..f555d034f799deedffc2f877754cab0f965a73c5 100644 --- a/src/displayapp/screens/settings/QuickSettings.h +++ b/src/displayapp/screens/settings/QuickSettings.h @@ -27,7 +27,7 @@ Controllers::Ble& bleController); ~QuickSettings() override; - void OnButtonEvent(lv_obj_t* object, lv_event_t event); + void OnButtonEvent(lv_obj_t* object); void UpdateScreen(); diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index 7581f18411bbb031de07648665f64459e61f53ad..47b786e46701de68babe07f37abf06675a8def23 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -5,6 +5,7 @@ #include #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" #include "components/settings/Settings.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -67,8 +68,7 @@ btnSetTime->user_data = this; lv_obj_set_size(btnSetTime, 120, 50); 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_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38)); - lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_MAKE(0x18, 0x18, 0x18)); + lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_value_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_GRAY); lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler); diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.cpp b/src/displayapp/screens/settings/SettingShakeThreshold.cpp index aac1eaff9485cf563c0dd7482155334edbad9e0d..de46f7de0c8b40e138177eec15ede4d1d4b93b6e 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.cpp +++ b/src/displayapp/screens/settings/SettingShakeThreshold.cpp @@ -3,6 +3,7 @@ #include #include "displayapp/DisplayApp.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -123,8 +124,7 @@ calibrating = 1; vCalTime = xTaskGetTickCount(); lv_label_set_text_static(calLabel, "Ready!"); lv_obj_set_click(positionArc, false); - lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); - lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0)); + lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, Colors::highlight); } else if (lv_btn_get_state(calButton) == LV_BTN_STATE_RELEASED) { calibrating = 0; lv_obj_set_click(positionArc, true); diff --git a/src/displayapp/screens/settings/SettingSteps.cpp b/src/displayapp/screens/settings/SettingSteps.cpp index e92600c2c70e84be99c4f5777d6a1798ca64e8a7..af5bd6e9118df7495059936ea6c05d4194674f60 100644 --- a/src/displayapp/screens/settings/SettingSteps.cpp +++ b/src/displayapp/screens/settings/SettingSteps.cpp @@ -17,7 +17,6 @@ : Screen(app), settingsController {settingsController} { lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - // lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111)); lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 3cb2a364639554576a00ce30c9be4127092d9c4e..be595a74f14a9e74dac06ec39cf52163ceda8ac9 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -21,7 +21,6 @@ : Screen(app), settingsController {settingsController} { lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - // lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111)); lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); diff --git a/src/displayapp/widgets/Counter.cpp b/src/displayapp/widgets/Counter.cpp index d8a1626e6e1f5d804801a390c9a194a9ea7d53a5..e95178ec11ed4977ab00c535b5963c6a27db8ef9 100644 --- a/src/displayapp/widgets/Counter.cpp +++ b/src/displayapp/widgets/Counter.cpp @@ -1,5 +1,6 @@ #include "displayapp/widgets/Counter.h" #include "components/datetime/DateTimeController.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Widgets; @@ -17,9 +18,17 @@ if (event == LV_EVENT_SHORT_CLICKED || event == LV_EVENT_LONG_PRESSED_REPEAT) { widget->DownBtnPressed(); } } + constexpr int digitCount(int number) { + int digitCount = 0; + while (number > 0) { + digitCount++; + number /= 10; + } + return digitCount; + } } -Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, font {font} { +Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, font {font}, leadingZeroCount {digitCount(max)} { } void Counter::UpBtnPressed() { @@ -71,14 +80,14 @@ if (twelveHourMode) { if (value == 0) { lv_label_set_text_static(number, "12"); } else if (value <= 12) { - lv_label_set_text_fmt(number, "%.2i", value); + lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value); } else { - lv_label_set_text_fmt(number, "%.2i", value - 12); + lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value - 12); } } else if (monthMode) { lv_label_set_text(number, Controllers::DateTime::MonthShortToStringLow(static_cast<Controllers::DateTime::Months>(value))); } else { - lv_label_set_text_fmt(number, "%.2i", value); + lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value); } } @@ -94,6 +103,8 @@ void Counter::EnableMonthMode() { monthMode = true; } +// Counter cannot be resized after creation, +// so the newMax value must have the same number of digits as the old one void Counter::SetMax(int newMax) { max = newMax; if (value > max) { @@ -108,10 +119,8 @@ this->ValueChangedHandler = handler; } void Counter::Create() { - constexpr lv_color_t bgColor = LV_COLOR_MAKE(0x38, 0x38, 0x38); - counterContainer = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); number = lv_label_create(counterContainer, nullptr); lv_obj_set_style_local_text_font(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &font); @@ -133,7 +142,7 @@ UpdateLabel(); upBtn = lv_btn_create(counterContainer, nullptr); - lv_obj_set_style_local_bg_color(upBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + lv_obj_set_style_local_bg_color(upBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_size(upBtn, width, btnHeight); lv_obj_align(upBtn, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); upBtn->user_data = this; @@ -145,7 +154,7 @@ lv_label_set_text_static(upLabel, "+"); lv_obj_align(upLabel, nullptr, LV_ALIGN_CENTER, 0, 0); downBtn = lv_btn_create(counterContainer, nullptr); - lv_obj_set_style_local_bg_color(downBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + lv_obj_set_style_local_bg_color(downBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_size(downBtn, width, btnHeight); lv_obj_align(downBtn, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); downBtn->user_data = this; diff --git a/src/displayapp/widgets/Counter.h b/src/displayapp/widgets/Counter.h index d38dd9d79976d5d97b9e2dbc8f2604415f90c0bb..825860b8d9e9b1accd1ed63e284e7f38aadc9deb 100644 --- a/src/displayapp/widgets/Counter.h +++ b/src/displayapp/widgets/Counter.h @@ -41,6 +41,7 @@ lv_point_t linePoints[2]; int min; int max; int value; + const int leadingZeroCount; bool twelveHourMode = false; bool monthMode = false; lv_font_t& font; diff --git a/src/displayapp/widgets/PageIndicator.cpp b/src/displayapp/widgets/PageIndicator.cpp index 06058beb1b3dab44a861ab17b963631b19a49233..84d03e7ed0b6191080653d07c6ba22971b84b361 100644 --- a/src/displayapp/widgets/PageIndicator.cpp +++ b/src/displayapp/widgets/PageIndicator.cpp @@ -1,4 +1,5 @@ #include "displayapp/widgets/PageIndicator.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Widgets; @@ -13,7 +14,7 @@ pageIndicatorBasePoints[1].y = LV_VER_RES; pageIndicatorBase = lv_line_create(lv_scr_act(), nullptr); lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); - lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111)); + lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2); const int16_t indicatorSize = LV_VER_RES / nScreens; @@ -26,6 +27,6 @@ pageIndicatorPoints[1].y = indicatorPos + indicatorSize; pageIndicator = lv_line_create(lv_scr_act(), nullptr); lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); - lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0)); + lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_line_set_points(pageIndicator, pageIndicatorPoints, 2); } diff --git a/src/displayapp/widgets/StatusIcons.cpp b/src/displayapp/widgets/StatusIcons.cpp index c1004b7702aaff73f5499a83086b3f269726d938..607f3745ae98313f33ca35853a30b09f4e4b8680 100644 --- a/src/displayapp/widgets/StatusIcons.cpp +++ b/src/displayapp/widgets/StatusIcons.cpp @@ -19,7 +19,7 @@ lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC)); lv_label_set_text_static(bleIcon, Screens::Symbols::bluetooth); batteryPlug = lv_label_create(container, nullptr); - lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); + lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); lv_label_set_text_static(batteryPlug, Screens::Symbols::plug); batteryIcon.Create(container); diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 3ed1beb4bcd240ea7157780d1752745e3c777e79..cfd5bd2ce4b8b42a0d93c3cbecc3a0c5dce17e58 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -21,7 +21,10 @@ ColMod(); MemoryDataAccessControl(); ColumnAddressSet(); RowAddressSet(); +// P8B Mirrored version does not need display inversion. +#ifndef DRIVER_DISPLAY_MIRROR DisplayInversionOn(); +#endif NormalModeOn(); SetVdv(); DisplayOn(); @@ -62,7 +65,18 @@ } void St7789::MemoryDataAccessControl() { WriteCommand(static_cast<uint8_t>(Commands::MemoryDataAccessControl)); +#ifdef DRIVER_DISPLAY_MIRROR + // [7] = MY = Page Address Order, 0 = Top to bottom, 1 = Bottom to top + // [6] = MX = Column Address Order, 0 = Left to right, 1 = Right to left + // [5] = MV = Page/Column Order, 0 = Normal mode, 1 = Reverse mode + // [4] = ML = Line Address Order, 0 = LCD refresh from top to bottom, 1 = Bottom to top + // [3] = RGB = RGB/BGR Order, 0 = RGB, 1 = BGR + // [2] = MH = Display Data Latch Order, 0 = LCD refresh from left to right, 1 = Right to left + // [0 .. 1] = Unused + WriteData(0b01000000); +#else WriteData(0x00); +#endif } void St7789::ColumnAddressSet() { diff --git a/src/libs/lv_conf.h b/src/libs/lv_conf.h index b3ff8f57583a4d96d33de2507ab8eeb3f1500308..00f6a1dffc55780925b3c1bd6a51a54a12e8f38d 100644 --- a/src/libs/lv_conf.h +++ b/src/libs/lv_conf.h @@ -161,7 +161,7 @@ /*1: enable outline drawing on rectangles*/ #define LV_USE_OUTLINE 0 /*1: enable pattern drawing on rectangles*/ -#define LV_USE_PATTERN 0 +#define LV_USE_PATTERN 1 /*1: enable value string drawing on rectangles*/ #define LV_USE_VALUE_STR 1 diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index d3f1278912b9903000b274c42994840fea086981..1c871fd2b3be9293d27b29d479e1e4c499bfcfb9 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -251,7 +251,8 @@ break; case Messages::TouchWakeUp: { if (touchHandler.GetNewTouchInfo()) { auto gesture = touchHandler.GestureGet(); - if (gesture != Pinetime::Applications::TouchEvents::None && + if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && + gesture != Pinetime::Applications::TouchEvents::None && ((gesture == Pinetime::Applications::TouchEvents::DoubleTap && settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) || (gesture == Pinetime::Applications::TouchEvents::Tap && @@ -280,7 +281,7 @@ alarmController.ScheduleAlarm(); } break; case Messages::OnNewNotification: - if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) { + if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) { if (state == SystemTaskState::Sleeping) { GoToRunning(); } else { @@ -388,7 +389,8 @@ stepCounterMustBeReset = true; break; case Messages::OnNewHour: using Pinetime::Controllers::AlarmController; - if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && + if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && + settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && alarmController.State() != AlarmController::AlarmState::Alerting) { if (state == SystemTaskState::Sleeping) { GoToRunning(); @@ -399,7 +401,8 @@ } break; case Messages::OnNewHalfHour: using Pinetime::Controllers::AlarmController; - if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && + if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && + settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && alarmController.State() != AlarmController::AlarmState::Alerting) { if (state == SystemTaskState::Sleeping) { GoToRunning(); @@ -483,13 +486,13 @@ motionController.IsSensorOk(motionSensor.IsOk()); motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) && - motionController.Should_RaiseWake(state == SystemTaskState::Sleeping)) { - GoToRunning(); - } - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) && - motionController.Should_ShakeWake(settingsController.GetShakeThreshold())) { - GoToRunning(); + if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) { + if ((settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) && + motionController.Should_RaiseWake(state == SystemTaskState::Sleeping)) || + (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) && + motionController.Should_ShakeWake(settingsController.GetShakeThreshold()))) { + GoToRunning(); + } } }