Merge remote-tracking branch 'upstream/develop' into pts-options
|
@ -1,7 +1,6 @@
|
||||||
# VS Code Dev Container
|
# 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
|
## Requirements
|
||||||
|
|
||||||
|
@ -35,16 +34,12 @@ There are also VS Code tasks provided should you desire to use those.
|
||||||
|
|
||||||
The task "update submodules" will update the git submodules
|
The task "update submodules" will update the git submodules
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
You can use the build.sh script located in /opt/
|
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
|
CMake is also configured and controls for the CMake plugin are available in VS Code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Debugging
|
### Debugging
|
||||||
|
|
||||||
Docker on windows does not support passing USB devices to the underlying WSL2 subsystem, To get around this we use OpenOCD in server mode running on the host.
|
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.
|
||||||
|
@ -55,6 +50,6 @@ 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
|
The default launch.json file expects OpenOCD to be listening on port 3333, edit if needed
|
||||||
|
|
||||||
|
|
||||||
## Current Issues
|
## 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
|
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
|
74
.github/workflows/lv_sim.yml
vendored
|
@ -1,74 +0,0 @@
|
||||||
# GitHub Actions Workflow to build Simulator for PineTime Smart Watch LVGL Interface
|
|
||||||
|
|
||||||
name: Build PineTime LVGL Simulator
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master, develop ]
|
|
||||||
paths-ignore:
|
|
||||||
- 'doc/**'
|
|
||||||
- 'images/**'
|
|
||||||
pull_request:
|
|
||||||
branches: [ develop ]
|
|
||||||
paths-ignore:
|
|
||||||
- 'doc/**'
|
|
||||||
- 'images/**'
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
|
|
||||||
#########################################################################################
|
|
||||||
# Download and Install Dependencies
|
|
||||||
|
|
||||||
- name: Install cmake
|
|
||||||
uses: lukka/get-cmake@v3.18.3
|
|
||||||
|
|
||||||
- name: Install SDL2 development package
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y install libsdl2-dev
|
|
||||||
|
|
||||||
- name: Install lv_font_conv
|
|
||||||
run:
|
|
||||||
npm i -g lv_font_conv@1.5.2
|
|
||||||
|
|
||||||
#########################################################################################
|
|
||||||
# Checkout
|
|
||||||
|
|
||||||
- name: Checkout source files
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
#########################################################################################
|
|
||||||
# get InfiniSim repo
|
|
||||||
|
|
||||||
- name: Get InfiniSim repo
|
|
||||||
run: |
|
|
||||||
git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main
|
|
||||||
git -C InfiniSim submodule update --init lv_drivers libpng
|
|
||||||
|
|
||||||
#########################################################################################
|
|
||||||
# CMake
|
|
||||||
|
|
||||||
- name: CMake
|
|
||||||
run: |
|
|
||||||
cmake -G Ninja -S InfiniSim -B build_lv_sim -DInfiniTime_DIR="${PWD}"
|
|
||||||
|
|
||||||
#########################################################################################
|
|
||||||
# Build and Upload simulator
|
|
||||||
|
|
||||||
- name: Build simulator executable
|
|
||||||
run: |
|
|
||||||
cmake --build build_lv_sim
|
|
||||||
|
|
||||||
- name: Upload simulator executable
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: infinisim-${{ github.head_ref }}
|
|
||||||
path: build_lv_sim/infinisim
|
|
53
.github/workflows/main.yml
vendored
|
@ -1,26 +1,18 @@
|
||||||
# GitHub Actions Workflow to build FreeRTOS Firmware for PineTime Smart Watch
|
name: CI
|
||||||
# See https://lupyuen.github.io/pinetime-rust-mynewt/articles/cloud
|
|
||||||
# Based on https://github.com/JF002/InfiniTime/blob/master/doc/buildAndProgram.md
|
|
||||||
# and https://github.com/JF002/InfiniTime/blob/master/bootloader/README.md
|
|
||||||
|
|
||||||
name: Build PineTime Firmware
|
|
||||||
|
|
||||||
|
# Run this workflow whenever the build may be affected
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, develop ]
|
branches: [ master, develop ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'doc/**'
|
- 'doc/**'
|
||||||
- 'images/**'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ develop ]
|
branches: [ develop ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'doc/**'
|
- 'doc/**'
|
||||||
- 'images/**'
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-firmware:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: infinitime/infinitime-build
|
image: infinitime/infinitime-build
|
||||||
|
@ -53,3 +45,42 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: InfiniTime MCUBoot image ${{ github.head_ref }}
|
name: InfiniTime MCUBoot image ${{ github.head_ref }}
|
||||||
path: ./build/output/pinetime-mcuboot-app-image-*.bin
|
path: ./build/output/pinetime-mcuboot-app-image-*.bin
|
||||||
|
|
||||||
|
build-simulator:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install cmake
|
||||||
|
uses: lukka/get-cmake@v3.18.3
|
||||||
|
|
||||||
|
- name: Install SDL2 development package
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install libsdl2-dev
|
||||||
|
|
||||||
|
- name: Install lv_font_conv
|
||||||
|
run:
|
||||||
|
npm i -g lv_font_conv@1.5.2
|
||||||
|
|
||||||
|
- name: Checkout source files
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Get InfiniSim repo
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main
|
||||||
|
git -C InfiniSim submodule update --init lv_drivers libpng
|
||||||
|
|
||||||
|
- name: CMake
|
||||||
|
run: |
|
||||||
|
cmake -G Ninja -S InfiniSim -B build_lv_sim -DInfiniTime_DIR="${PWD}"
|
||||||
|
|
||||||
|
- name: Build simulator executable
|
||||||
|
run: |
|
||||||
|
cmake --build build_lv_sim
|
||||||
|
|
||||||
|
- name: Upload simulator executable
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: infinisim-${{ github.head_ref }}
|
||||||
|
path: build_lv_sim/infinisim
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[![Build PineTime Firmware](https://github.com/InfiniTimeOrg/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/InfiniTimeOrg/InfiniTime/actions)
|
[![Build PineTime Firmware](https://github.com/InfiniTimeOrg/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/InfiniTimeOrg/InfiniTime/actions)
|
||||||
|
|
||||||
![InfiniTime logo](images/infinitime-logo-small.jpg "InfiniTime Logo")
|
![InfiniTime logo](doc/logo/infinitime-logo-small.jpg "InfiniTime Logo")
|
||||||
|
|
||||||
Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++.
|
Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++.
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p
|
||||||
This project is released under the GNU General Public License version 3 or, at your option, any later version.
|
This project is released under the GNU General Public License version 3 or, at your option, any later version.
|
||||||
|
|
||||||
It integrates the following projects:
|
It integrates the following projects:
|
||||||
|
|
||||||
- RTOS : **[FreeRTOS](https://freertos.org)** under the MIT license
|
- RTOS : **[FreeRTOS](https://freertos.org)** under the MIT license
|
||||||
- UI : **[LittleVGL/LVGL](https://lvgl.io/)** 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
|
- BLE stack : **[NimBLE](https://github.com/apache/mynewt-nimble)** under the Apache 2.0 license
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# About this bootloader
|
# 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 [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.
|
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 @@ When it is run, this bootloader looks in the SPI flash memory if a new firmware
|
||||||
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.
|
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
|
# 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.
|
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.
|
||||||
|
|
||||||
![MCUBoot boot sequence diagram](../doc/bootloader/boot.png "MCUBoot boot sequence diagram")
|
![MCUBoot boot sequence diagram](../doc/bootloader/boot.png "MCUBoot boot sequence diagram")
|
||||||
|
@ -19,6 +21,7 @@ MCUBoot is run at boot time. In normal operation, it just jumps to the reset han
|
||||||
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.
|
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' :
|
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 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 secondary slot** : it is used to store the upgraded version of the firmware, when available.
|
||||||
|
|
||||||
|
@ -35,6 +38,7 @@ The next time MCUBoot will be run (after a MCU reset), MCUBoot will check if the
|
||||||
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.
|
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
|
# Degraded cases
|
||||||
|
|
||||||
This chapter describes degraded cases that are handled by our bootloader and those that are not supported.
|
This chapter describes degraded cases that are handled by our bootloader and those that are not supported.
|
||||||
|
|
||||||
Case | Current bootloader | Solution
|
Case | Current bootloader | Solution
|
||||||
|
@ -50,16 +54,19 @@ New firmware does not run properly but sets the valid bit and refreshes the watc
|
||||||
# Using the bootloader
|
# Using the bootloader
|
||||||
|
|
||||||
## Bootloader graphic
|
## 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 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 :
|
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:
|
- Build:
|
||||||
```
|
|
||||||
$ make pinetime-graphics
|
```sh
|
||||||
|
make pinetime-graphics
|
||||||
```
|
```
|
||||||
|
|
||||||
- Program (using OpenOCD for example) :
|
- Program (using OpenOCD for example) :
|
||||||
|
|
||||||
```
|
```
|
||||||
program pinetime-graphics.bin 0
|
program pinetime-graphics.bin 0
|
||||||
```
|
```
|
||||||
|
@ -67,55 +74,53 @@ 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
|
## Bootloader binary
|
||||||
|
|
||||||
The binary comes from https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4
|
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.
|
It must be flash at address **0x00** in the internal flash memory.
|
||||||
|
|
||||||
Using OpenOCD:
|
Using OpenOCD:
|
||||||
|
|
||||||
`
|
`program bootloader-5.0.4.bin 0`
|
||||||
program bootloader-5.0.4.bin 0
|
|
||||||
`
|
|
||||||
|
|
||||||
## Application firmware image
|
## Application firmware image
|
||||||
|
|
||||||
Build the binary compatible with the booloader:
|
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*.
|
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:
|
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:
|
||||||
|
|
||||||
`
|
```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
|
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.
|
The image must be then flashed at address **0x8000** in the internal flash memory.
|
||||||
|
|
||||||
Using OpenOCD:
|
Using OpenOCD:
|
||||||
|
|
||||||
`
|
`program image.bin 0x8000`
|
||||||
program image.bin 0x8000
|
|
||||||
`
|
|
||||||
|
|
||||||
## OTA and DFU
|
## OTA and DFU
|
||||||
|
|
||||||
Pack the image into a .zip file for the NRF DFU protocol:
|
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
|
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:
|
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
|
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).
|
**Note** : dfu.py is a slightly modified version of [this repo](https://github.com/daniel-thompson/ota-dfu-python).
|
||||||
|
|
||||||
### Firmware validation
|
### 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.
|
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.
|
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.
|
||||||
|
|
|
@ -17,24 +17,24 @@ This is a Python program that uses `gatttool` (provided with the Linux BlueZ dri
|
||||||
|
|
||||||
### Main features:
|
### Main features:
|
||||||
|
|
||||||
* Perform OTA DFU to an nRF5 peripheral without an external USB BLE dongle.
|
- 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).
|
- 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.
|
- 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).
|
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
|
## Prerequisites
|
||||||
|
|
||||||
* BlueZ 5.4 or above
|
- BlueZ 5.4 or above
|
||||||
* Python 3.6
|
- Python 3.6
|
||||||
* Python `pexpect` module (available via pip)
|
- Python `pexpect` module (available via pip)
|
||||||
* Python `intelhex` module (available via pip)
|
- Python `intelhex` module (available via pip)
|
||||||
|
|
||||||
## Firmware Build Requirement
|
## Firmware Build Requirement
|
||||||
|
|
||||||
* Your nRF5 peripheral firmware build method will produce a firmware file ending with either `*.hex` or `*.bin`.
|
- 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`.
|
- 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.
|
- The typical naming convention is `application.bin` and `application.dat`, but this utility will accept other names.
|
||||||
|
|
||||||
## Generating init files
|
## Generating init files
|
||||||
|
|
||||||
|
@ -75,7 +75,6 @@ You can use the `hcitool lescan` to figure out the address of a DFU target, for
|
||||||
CD:E3:4A:47:1C:E4 <TARGET_NAME>
|
CD:E3:4A:47:1C:E4 <TARGET_NAME>
|
||||||
CD:E3:4A:47:1C:E4 (unknown)
|
CD:E3:4A:47:1C:E4 (unknown)
|
||||||
|
|
||||||
|
|
||||||
## Example Output
|
## Example Output
|
||||||
|
|
||||||
================================
|
================================
|
||||||
|
@ -105,14 +104,14 @@ You can use the `hcitool lescan` to figure out the address of a DFU target, for
|
||||||
|
|
||||||
## TODO:
|
## TODO:
|
||||||
|
|
||||||
* Implement link-loss procedure for Legacy Controller.
|
- Implement link-loss procedure for Legacy Controller.
|
||||||
* Update example output in readme.
|
- Update example output in readme.
|
||||||
* Add makefile examples.
|
- Add makefile examples.
|
||||||
* More code cleanup.
|
- More code cleanup.
|
||||||
|
|
||||||
## Info & References
|
## 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 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 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)
|
- [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)
|
- [nrfutil](https://github.com/NordicSemiconductor/pc-nrfutil)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# BLE FS
|
# 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.
|
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.
|
||||||
|
@ -133,8 +134,8 @@ The response to this packet will be as follows. Responses will be sent until the
|
||||||
- Unsigned 32-bit integer encoding the entry number
|
- Unsigned 32-bit integer encoding the entry number
|
||||||
- Unsigned 32-bit integer encoding the total amount of entries
|
- Unsigned 32-bit integer encoding the total amount of entries
|
||||||
- Flags: unsigned 32-bit integer
|
- Flags: unsigned 32-bit integer
|
||||||
+ Bit 0: Set when entry is a directory
|
- Bit 0: Set when entry is a directory
|
||||||
+ Bits 1-7: Reserved
|
- Bits 1-7: Reserved
|
||||||
- Unsigned 64-bit integer encoding the unix timestamp of the modification time with nanosecond resolution
|
- 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
|
- Unsigned 32-bit integer encoding the size of the file
|
||||||
- Path: UTF-8 encoded string that is _not_ null terminated.
|
- Path: UTF-8 encoded string that is _not_ null terminated.
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Memory analysis
|
# Memory analysis
|
||||||
|
|
||||||
The PineTime is equipped with the following memories:
|
The PineTime is equipped with the following memories:
|
||||||
|
|
||||||
- The internal RAM : **64KB**
|
- The internal RAM : **64KB**
|
||||||
- The internal Flash : **512KB**
|
- The internal Flash : **512KB**
|
||||||
- The external (SPI) Flash : **4MB**
|
- The external (SPI) Flash : **4MB**
|
||||||
|
@ -9,6 +11,7 @@ Note that the NRF52832 cannot execute code stored in the external flash : we nee
|
||||||
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).
|
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
|
## 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.
|
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:
|
Here is a small description of these sections and where they end up in memory:
|
||||||
|
@ -18,8 +21,8 @@ Here is a small description of these sections and where they end up in memory:
|
||||||
- **DATA** = initialized variables (FLASH + RAM)
|
- **DATA** = initialized variables (FLASH + RAM)
|
||||||
- **BSS** = uninitialized variables (RAM)
|
- **BSS** = uninitialized variables (RAM)
|
||||||
|
|
||||||
|
|
||||||
## Internal FLASH
|
## Internal FLASH
|
||||||
|
|
||||||
The internal flash memory stores the whole firmware: code, variable that are not default-initialized, constants...
|
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.
|
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,6 +44,7 @@ Using this tool, you can compare the relative size of symbols. This can be helpf
|
||||||
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...
|
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
|
||||||
|
|
||||||
[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](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](./memoryAnalysis/puncover.png)
|
![Puncover](./memoryAnalysis/puncover.png)
|
||||||
|
|
||||||
|
@ -53,13 +57,14 @@ Puncover is really easy to install:
|
||||||
- Install : `pip install .`
|
- 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`
|
- 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
|
- Replace
|
||||||
* `/path/to/gcc-arm-none-eabi-10.3-2021.10/bin` with the path to your gcc-arm-none-eabi toolchain
|
- `/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/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/sources` with the path to the root folder of the sources (checkout directory)
|
||||||
* `/path/to/build/directory` with the path to the build directory
|
- `/path/to/build/directory` with the path to the build directory
|
||||||
- Launch a browser at http://localhost:5000/
|
- Launch a browser at http://localhost:5000/
|
||||||
|
|
||||||
### Analysis
|
### 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.
|
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.
|
||||||
|
|
||||||
![Puncover](./memoryAnalysis/puncover-all-symbols.png)
|
![Puncover](./memoryAnalysis/puncover-all-symbols.png)
|
||||||
|
@ -69,18 +74,22 @@ This way, you can easily check what needs to be optimized. We should find a way
|
||||||
It's always a good idea to check the flash memory space when working on the project. This way, you can easily check that your developments are using a reasonable amount of space.
|
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
|
### Links
|
||||||
|
|
||||||
- Analysis with linkermapviz : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620
|
- 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 Puncover : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-847311392
|
||||||
|
|
||||||
## RAM
|
## RAM
|
||||||
|
|
||||||
RAM memory contains all the data that can be modified at run-time: variables, stack, heap...
|
RAM memory contains all the data that can be modified at run-time: variables, stack, heap...
|
||||||
|
|
||||||
### Data
|
### Data
|
||||||
|
|
||||||
RAM memory can be *statically* allocated, meaning that the size and position of the data are known at compile-time:
|
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.
|
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.
|
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]
|
||||||
|
|
||||||
|
@ -90,13 +99,16 @@ int main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Analysis
|
#### 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
|
### 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).
|
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.
|
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:
|
#### 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:
|
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 @@ bne .L_fill
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Dump RAM memory and check usage
|
#### Dump RAM memory and check usage
|
||||||
|
|
||||||
Dumping the content of the ram is easy using JLink debugger and `nrfjprog`:
|
Dumping the content of the ram is easy using JLink debugger and `nrfjprog`:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -194,12 +207,15 @@ On the following dump, the maximum stack usage is 520 bytes (0xFFFF - 0xFDF8):
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Analysis
|
#### Analysis
|
||||||
|
|
||||||
According to my experimentations, we don't use the stack that much, and 8192 bytes is probably way too big for InfiniTime!
|
According to my experimentations, we don't use the stack that much, and 8192 bytes is probably way too big for InfiniTime!
|
||||||
|
|
||||||
#### Links
|
#### Links
|
||||||
|
|
||||||
- https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035070
|
- https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035070
|
||||||
|
|
||||||
### Heap
|
### 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`...).
|
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:
|
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
|
#### 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.
|
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:
|
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 @@ void* __wrap_malloc(size_t 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()`.
|
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):
|
Using this technique, I was able to trace all malloc calls at boot (boot -> digital watchface):
|
||||||
|
@ -239,12 +257,14 @@ Using this technique, I was able to trace all malloc calls at boot (boot -> digi
|
||||||
- hr task = 304
|
- hr task = 304
|
||||||
|
|
||||||
#### Links
|
#### Links
|
||||||
|
|
||||||
- https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035625
|
- https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035625
|
||||||
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-1-calculating-stack-size/
|
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-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-2-properly-allocating-stacks/
|
||||||
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-3-avoiding-heap-errors/
|
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-3-avoiding-heap-errors/
|
||||||
|
|
||||||
## LVGL
|
## LVGL
|
||||||
|
|
||||||
I did a deep analysis of the usage of the buffer dedicated to lvgl (managed by lv_mem).
|
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.
|
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.
|
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).
|
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
|
### 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 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 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...).
|
FreeRTOS uses this buffer to allocate memory for tasks stack and all the RTOS object created during runtime (timers, mutexes...).
|
||||||
|
|
||||||
|
@ -276,7 +298,6 @@ The function `xPortGetFreeHeapSize()` returns the amount of memory available in
|
||||||
NRF_LOG_INFO("Free heap : %d", xPortGetFreeHeapSize());
|
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:
|
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++) {
|
for (int i = 0; i < nb; i++) {
|
||||||
NRF_LOG_INFO("Task [%s] - %d", tasksStatus[i].pcTaskName, tasksStatus[i].usStackHighWaterMark);
|
NRF_LOG_INFO("Task [%s] - %d", tasksStatus[i].pcTaskName, tasksStatus[i].usStackHighWaterMark);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
# Motion Service
|
# Motion Service
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
The motion service exposes step count and raw X/Y/Z motion value as READ and NOTIFY characteristics.
|
The motion service exposes step count and raw X/Y/Z motion value as READ and NOTIFY characteristics.
|
||||||
|
|
||||||
## Service
|
## Service
|
||||||
|
|
||||||
The service UUID is **00030000-78fc-48fe-8e23-433b3a1942d0**
|
The service UUID is **00030000-78fc-48fe-8e23-433b3a1942d0**
|
||||||
|
|
||||||
## Characteristics
|
## Characteristics
|
||||||
|
|
||||||
### Step count (UUID 00030001-78fc-48fe-8e23-433b3a1942d0)
|
### Step count (UUID 00030001-78fc-48fe-8e23-433b3a1942d0)
|
||||||
|
|
||||||
The current number of steps represented as a single `uint32_t` (4 bytes) value.
|
The current number of steps represented as a single `uint32_t` (4 bytes) value.
|
||||||
|
|
||||||
### Raw motion values (UUID 00030002-78fc-48fe-8e23-433b3a1942d0)
|
### Raw motion values (UUID 00030002-78fc-48fe-8e23-433b3a1942d0)
|
||||||
|
|
||||||
The current raw motion values. This is a 3 `int16_t` array:
|
The current raw motion values. This is a 3 `int16_t` array:
|
||||||
|
|
||||||
- [0] : X
|
- [0] : X
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Navigation Service
|
# Navigation Service
|
||||||
|
|
||||||
## Introduction
|
## 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 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:
|
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
|
progress (uint8) - Percent complete of total route, value 0-100
|
||||||
|
|
||||||
## Service
|
## Service
|
||||||
|
|
||||||
The service UUID is 00010000-78fc-48fe-8e23-433b3a1942d0
|
The service UUID is 00010000-78fc-48fe-8e23-433b3a1942d0
|
||||||
|
|
||||||
## Characteristics
|
## Characteristics
|
||||||
|
|
||||||
## Flags (UUID 00010001-78fc-48fe-8e23-433b3a1942d0)
|
## Flags (UUID 00010001-78fc-48fe-8e23-433b3a1942d0)
|
||||||
|
|
||||||
All included icons are from pure-maps, which provides the actual routing from the client. The icon names ultimately come from the mapbox project "direction-icons", See https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation See the end of this document for the full list of supported icon names.
|
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)
|
## 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".
|
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)
|
## Man Dist (UUID 00010003-78fc-48fe-8e23-433b3a1942d0)
|
||||||
|
|
||||||
This is a short string describing the distance to the upcoming instruction such as "50 m".
|
This is a short string describing the distance to the upcoming instruction such as "50 m".
|
||||||
|
|
||||||
## Progress (UUID 00010004-78fc-48fe-8e23-433b3a1942d0)
|
## Progress (UUID 00010004-78fc-48fe-8e23-433b3a1942d0)
|
||||||
|
|
||||||
The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
|
The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
|
||||||
|
|
||||||
## Full icon list
|
## Full icon list
|
||||||
* arrive
|
|
||||||
* arrive-left
|
- arrive
|
||||||
* arrive-right
|
- arrive-left
|
||||||
* arrive-straight
|
- arrive-right
|
||||||
* close
|
- arrive-straight
|
||||||
* continue
|
- close
|
||||||
* continue-left
|
- continue
|
||||||
* continue-right
|
- continue-left
|
||||||
* continue-slight-left
|
- continue-right
|
||||||
* continue-slight-right
|
- continue-slight-left
|
||||||
* continue-straight
|
- continue-slight-right
|
||||||
* continue-uturn
|
- continue-straight
|
||||||
* depart
|
- continue-uturn
|
||||||
* depart-left
|
- depart
|
||||||
* depart-right
|
- depart-left
|
||||||
* depart-straight
|
- depart-right
|
||||||
* end-of-road-left
|
- depart-straight
|
||||||
* end-of-road-right
|
- end-of-road-left
|
||||||
* ferry
|
- end-of-road-right
|
||||||
* flag
|
- ferry
|
||||||
* fork
|
- flag
|
||||||
* fork-left
|
- fork
|
||||||
* fork-right
|
- fork-left
|
||||||
* fork-slight-left
|
- fork-right
|
||||||
* fork-slight-right
|
- fork-slight-left
|
||||||
* fork-straight
|
- fork-slight-right
|
||||||
* invalid
|
- fork-straight
|
||||||
* invalid-left
|
- invalid
|
||||||
* invalid-right
|
- invalid-left
|
||||||
* invalid-slight-left
|
- invalid-right
|
||||||
* invalid-slight-right
|
- invalid-slight-left
|
||||||
* invalid-straight
|
- invalid-slight-right
|
||||||
* invalid-uturn
|
- invalid-straight
|
||||||
* merge-left
|
- invalid-uturn
|
||||||
* merge-right
|
- merge-left
|
||||||
* merge-slight-left
|
- merge-right
|
||||||
* merge-slight-right
|
- merge-slight-left
|
||||||
* merge-straight
|
- merge-slight-right
|
||||||
* new-name-left
|
- merge-straight
|
||||||
* new-name-right
|
- new-name-left
|
||||||
* new-name-sharp-left
|
- new-name-right
|
||||||
* new-name-sharp-right
|
- new-name-sharp-left
|
||||||
* new-name-slight-left
|
- new-name-sharp-right
|
||||||
* new-name-slight-right
|
- new-name-slight-left
|
||||||
* new-name-straight
|
- new-name-slight-right
|
||||||
* notification-left
|
- new-name-straight
|
||||||
* notification-right
|
- notification-left
|
||||||
* notification-sharp-left
|
- notification-right
|
||||||
* notification-sharp-right
|
- notification-sharp-left
|
||||||
* notification-slight-left
|
- notification-sharp-right
|
||||||
* notification-slight-right
|
- notification-slight-left
|
||||||
* notification-straight
|
- notification-slight-right
|
||||||
* off-ramp-left
|
- notification-straight
|
||||||
* off-ramp-right
|
- off-ramp-left
|
||||||
* off-ramp-sharp-left
|
- off-ramp-right
|
||||||
* off-ramp-sharp-right
|
- off-ramp-sharp-left
|
||||||
* off-ramp-slight-left
|
- off-ramp-sharp-right
|
||||||
* off-ramp-slight-right
|
- off-ramp-slight-left
|
||||||
* off-ramp-straight
|
- off-ramp-slight-right
|
||||||
* on-ramp-left
|
- off-ramp-straight
|
||||||
* on-ramp-right
|
- on-ramp-left
|
||||||
* on-ramp-sharp-left
|
- on-ramp-right
|
||||||
* on-ramp-sharp-right
|
- on-ramp-sharp-left
|
||||||
* on-ramp-slight-left
|
- on-ramp-sharp-right
|
||||||
* on-ramp-slight-right
|
- on-ramp-slight-left
|
||||||
* on-ramp-straight
|
- on-ramp-slight-right
|
||||||
* rotary
|
- on-ramp-straight
|
||||||
* rotary-left
|
- rotary
|
||||||
* rotary-right
|
- rotary-left
|
||||||
* rotary-sharp-left
|
- rotary-right
|
||||||
* rotary-sharp-right
|
- rotary-sharp-left
|
||||||
* rotary-slight-left
|
- rotary-sharp-right
|
||||||
* rotary-slight-right
|
- rotary-slight-left
|
||||||
* rotary-straight
|
- rotary-slight-right
|
||||||
* roundabout
|
- rotary-straight
|
||||||
* roundabout-left
|
- roundabout
|
||||||
* roundabout-right
|
- roundabout-left
|
||||||
* roundabout-sharp-left
|
- roundabout-right
|
||||||
* roundabout-sharp-right
|
- roundabout-sharp-left
|
||||||
* roundabout-slight-left
|
- roundabout-sharp-right
|
||||||
* roundabout-slight-right
|
- roundabout-slight-left
|
||||||
* roundabout-straight
|
- roundabout-slight-right
|
||||||
* turn-left
|
- roundabout-straight
|
||||||
* turn-right
|
- turn-left
|
||||||
* turn-sharp-left
|
- turn-right
|
||||||
* turn-sharp-right
|
- turn-sharp-left
|
||||||
* turn-slight-left
|
- turn-sharp-right
|
||||||
* turn-slight-right
|
- turn-slight-left
|
||||||
* turn-stright
|
- turn-slight-right
|
||||||
* updown
|
- turn-stright
|
||||||
* uturn
|
- updown
|
||||||
|
- uturn
|
||||||
|
|
|
@ -1,33 +1,36 @@
|
||||||
# Build a stub for PineTime using NRF52-DK
|
# Build a stub for PineTime using NRF52-DK
|
||||||
|
|
||||||
[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official development kit for the NRF52832 SoC from Nordic Semiconductor used in the PineTime.
|
[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:
|
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 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:
|
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
|
- heart rate sensor
|
||||||
* touchpad
|
- SPI flash
|
||||||
* accelerometer
|
- touchpad
|
||||||
|
- accelerometer
|
||||||
|
|
||||||
These devices could be added on this stub, but I do not have the parts to try them out for now.
|
These devices could be added on this stub, but I do not have the parts to try them out for now.
|
||||||
|
|
||||||
![Pinetime stub](../images/pinetimestub1.jpg "PinetimeStub")
|
![Pinetime stub](../images/pinetimestub1.jpg "PinetimeStub")
|
||||||
|
|
||||||
|
|
||||||
Here are the parts you need to build this simulator:
|
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))
|
- [NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK)
|
||||||
* A push-button (the one I use comes from a previous project build around ESP8266 board Wemos D1 Mini).
|
- An ST7889 display (I bought [this one](https://www.aliexpress.com/item/32859772356.html?spm=a2g0s.9042311.0.0.1b774c4dSoc4Xz))
|
||||||
* Dupont wires
|
- 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:
|
You just need to make the following connections:
|
||||||
|
|
||||||
| NRF52-DK | ST7889 display |
|
| NRF52-DK | ST7889 display |
|
||||||
| ---------|--------------- |
|
| -------- | -------------- |
|
||||||
| VDD | VCC |
|
| VDD | VCC |
|
||||||
| GND | GND |
|
| GND | GND |
|
||||||
| P0.03 | SDA |
|
| P0.03 | SDA |
|
||||||
|
@ -35,9 +38,8 @@ You just need to make the following connections:
|
||||||
| P0.02 | SCL |
|
| P0.02 | SCL |
|
||||||
| P0.18 | DC |
|
| P0.18 | DC |
|
||||||
|
|
||||||
|
|
||||||
| NRF52-DK | Push Button |
|
| NRF52-DK | Push Button |
|
||||||
| ---------|----------------------- |
|
| -------- | ------------------------- |
|
||||||
| P0.13 | Button IN (D3 in my case) |
|
| P0.13 | Button IN (D3 in my case) |
|
||||||
| GND | GND |
|
| GND | GND |
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# The SPI LCD driver
|
# The SPI LCD driver
|
||||||
|
|
||||||
## Introduction
|
## 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:
|
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
|
- an on-chip display data RAM that can store the whole framebuffer
|
||||||
- partial screen update
|
- partial screen update
|
||||||
- hardware assisted vertical scrolling
|
- hardware assisted vertical scrolling
|
||||||
|
@ -11,6 +14,7 @@ When you want to write a device driver for a specific component, its datasheet i
|
||||||
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:
|
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;
|
- 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;
|
- Then, I tried to display some pixels on the screen;
|
||||||
- Next, I wanted to display squares, colors and text;
|
- Next, I wanted to display squares, colors and text;
|
||||||
|
@ -20,12 +24,14 @@ In this document, I'll try to explain the process I've followed to write a devic
|
||||||
I'll describe all these steps in the following chapters.
|
I'll describe all these steps in the following chapters.
|
||||||
|
|
||||||
## The datasheet
|
## 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.
|
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.
|
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.
|
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 :
|
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
|
- 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
|
- Display Data Ram : how is the memory organized
|
||||||
- Power On/Off sequence
|
- Power On/Off sequence
|
||||||
|
@ -33,7 +39,6 @@ You'll want to read some part with more attention :
|
||||||
|
|
||||||
## One Pixel at a time
|
## One Pixel at a time
|
||||||
|
|
||||||
|
|
||||||
## Bulk transfers
|
## Bulk transfers
|
||||||
|
|
||||||
## DMA
|
## DMA
|
||||||
|
@ -41,6 +46,7 @@ You'll want to read some part with more attention :
|
||||||
## IRQ
|
## IRQ
|
||||||
|
|
||||||
## Bare metal integration
|
## Bare metal integration
|
||||||
|
|
||||||
Integration customisée dans la lib GFX que j'ai écrite
|
Integration customisée dans la lib GFX que j'ai écrite
|
||||||
|
|
||||||
## Integration with LittleVGL
|
## Integration with LittleVGL
|
|
@ -1,4 +1,5 @@
|
||||||
# How to flash InfiniTime using the SWD interface
|
# 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:
|
Download the files **bootloader.bin**, **image-x.y.z.bin** and **pinetime-graphics-x.y.z.bin** from the release page:
|
||||||
|
|
||||||
![Image file](gettingStarted/imageFile.png)
|
![Image file](gettingStarted/imageFile.png)
|
||||||
|
|
18
doc/ble.md
|
@ -1,5 +1,7 @@
|
||||||
# Bluetooth Low-Energy :
|
# Bluetooth Low-Energy :
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
This page describes the BLE implementation and API built in this firmware.
|
This page describes the BLE implementation and API built in this firmware.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -38,6 +40,7 @@ This page describes the BLE implementation and API built in this firmware.
|
||||||
---
|
---
|
||||||
|
|
||||||
## BLE Connection
|
## 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.
|
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.
|
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,6 +61,7 @@ The documentation for BLE FS can be found here:
|
||||||
---
|
---
|
||||||
|
|
||||||
## BLE UUIDs
|
## 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:
|
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:
|
||||||
|
@ -71,33 +75,37 @@ When the service does not exist in the BLE specification, InfiniTime implements
|
||||||
The following custom services are implemented in InfiniTime:
|
The following custom services are implemented in InfiniTime:
|
||||||
|
|
||||||
- Since InfiniTime 0.8:
|
- Since InfiniTime 0.8:
|
||||||
* Music Service : 00000000-78fc-48fe-8e23-433b3a1942d0
|
|
||||||
|
|
||||||
|
- Music Service : `00000000-78fc-48fe-8e23-433b3a1942d0`
|
||||||
|
|
||||||
- Since InfiniTime 0.11:
|
- Since InfiniTime 0.11:
|
||||||
* [Navigation Service](NavigationService.md) : 00010000-78fc-48fe-8e23-433b3a1942d0
|
|
||||||
|
|
||||||
|
- [Navigation Service](NavigationService.md) : `00010000-78fc-48fe-8e23-433b3a1942d0`
|
||||||
|
|
||||||
- Since InfiniTime 0.13
|
- 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:
|
- 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:
|
- 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
|
## BLE services
|
||||||
|
|
||||||
[List of standard BLE services](https://www.bluetooth.com/specifications/gatt/services/)
|
[List of standard BLE services](https://www.bluetooth.com/specifications/gatt/services/)
|
||||||
|
|
||||||
### CTS
|
### CTS
|
||||||
|
|
||||||
[Current Time Service](https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.current_time.xml)
|
[Current Time Service](https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.current_time.xml)
|
||||||
|
|
||||||
### ANS
|
### ANS
|
||||||
|
|
||||||
[Alert Notification Service](https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.alert_notification.xml)
|
[Alert Notification Service](https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.alert_notification.xml)
|
||||||
|
|
||||||
![ANS sequence diagram](./ble/ans_sequence.png "ANS sequence diagram")
|
![ANS sequence diagram](./ble/ans_sequence.png "ANS sequence diagram")
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Branches
|
# 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 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:
|
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.
|
- **master** : this branch is always ready to be deployed. It means that at any time, we should be able to build the branch and release a new version of the application.
|
||||||
- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable.
|
- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# Build
|
# Build
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
To build this project, you'll need:
|
To build this project, you'll need:
|
||||||
|
|
||||||
- A cross-compiler : [ARM-GCC (10.3-2021.10)](https://developer.arm.com/downloads/-/gnu-rm)
|
- 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 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))
|
- The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt))
|
||||||
|
@ -18,7 +21,9 @@ To build this project, you'll need:
|
||||||
- install lv_font_conv: `npm install lv_font_conv`
|
- install lv_font_conv: `npm install lv_font_conv`
|
||||||
|
|
||||||
## Build steps
|
## Build steps
|
||||||
|
|
||||||
### Clone the repo
|
### Clone the repo
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/InfiniTimeOrg/InfiniTime.git
|
git clone https://github.com/InfiniTimeOrg/InfiniTime.git
|
||||||
cd InfiniTime
|
cd InfiniTime
|
||||||
|
@ -26,7 +31,9 @@ git submodule update --init
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Project generation using CMake
|
### Project generation using CMake
|
||||||
|
|
||||||
CMake configures the project according to variables you specify the command line. The variables are:
|
CMake configures the project according to variables you specify the command line. The variables are:
|
||||||
|
|
||||||
Variable | Description | Example|
|
Variable | Description | Example|
|
||||||
|
@ -41,31 +48,36 @@ CMake configures the project according to variables you specify the command line
|
||||||
**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1`
|
**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)
|
**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.
|
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.
|
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.
|
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 command line for JLink
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_JLINK=1 -DNRFJPROG=... ../
|
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_JLINK=1 -DNRFJPROG=... ../
|
||||||
```
|
```
|
||||||
|
|
||||||
#### CMake command line for GDB Client (Black Magic Probe)
|
#### 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 -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 command line for OpenOCD
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] ../
|
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] ../
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build the project
|
### Build the project
|
||||||
|
|
||||||
During the project generation, CMake created the following targets:
|
During the project generation, CMake created the following targets:
|
||||||
|
|
||||||
- **FLASH_ERASE** : mass erase the flash memory of the NRF52.
|
- **FLASH_ERASE** : mass erase the flash memory of the NRF52.
|
||||||
- **FLASH_pinetime-app** : flash the firmware into the NRF52.
|
- **FLASH_pinetime-app** : flash the firmware into the NRF52.
|
||||||
- **pinetime-app** : build the standalone (without bootloader support) version of the firmware.
|
- **pinetime-app** : build the standalone (without bootloader support) version of the firmware.
|
||||||
|
@ -78,12 +90,14 @@ During the project generation, CMake created the following targets:
|
||||||
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.
|
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:
|
Build:
|
||||||
|
|
||||||
```
|
```
|
||||||
make -j pinetime-app
|
make -j pinetime-app
|
||||||
```
|
```
|
||||||
|
|
||||||
List of files generated:
|
List of files generated:
|
||||||
Binary files are generated into the folder `src`:
|
Binary files are generated into the folder `src`:
|
||||||
|
|
||||||
- **pinetime-app.bin, .hex and .out** : standalone firmware in bin, hex and out formats.
|
- **pinetime-app.bin, .hex and .out** : standalone firmware in bin, hex and out formats.
|
||||||
- **pinetime-app.map** : map file
|
- **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.bin, .hex and .out** : firmware with bootloader support in bin, hex and out formats.
|
||||||
|
@ -93,43 +107,52 @@ Binary files are generated into the folder `src`:
|
||||||
|
|
||||||
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
|
### Program and run
|
||||||
|
|
||||||
#### Using CMake targets
|
#### Using CMake targets
|
||||||
|
|
||||||
These target have been configured during the project generation by CMake according to the parameters you provided to the command line.
|
These target have been configured during the project generation by CMake according to the parameters you provided to the command line.
|
||||||
|
|
||||||
Mass erase:
|
Mass erase:
|
||||||
|
|
||||||
```
|
```
|
||||||
make FLASH_ERASE
|
make FLASH_ERASE
|
||||||
```
|
```
|
||||||
|
|
||||||
Flash the application:
|
Flash the application:
|
||||||
|
|
||||||
```
|
```
|
||||||
make FLASH_pinetime-app
|
make FLASH_pinetime-app
|
||||||
```
|
```
|
||||||
|
|
||||||
### How to generate files needed by the factory
|
### 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.
|
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).
|
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
|
#### merged-internal.hex
|
||||||
|
|
||||||
First, convert the bootloader to 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).
|
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:
|
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
|
<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).
|
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).
|
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**:
|
Finally, merge them together with **mergehex**:
|
||||||
|
|
||||||
```
|
```
|
||||||
/opt/mergehex/mergehex -m ./bootloader.hex ./pinetime-mcuboot-app-image-1.6.0.hex -o merged-internal.hex
|
/opt/mergehex/mergehex -m ./bootloader.hex ./pinetime-mcuboot-app-image-1.6.0.hex -o merged-internal.hex
|
||||||
```
|
```
|
||||||
|
@ -137,4 +160,5 @@ Finally, merge them together with **mergehex**:
|
||||||
This file must be flashed at offset **0x00** of the internal memory of the NRF52832.
|
This file must be flashed at offset **0x00** of the internal memory of the NRF52832.
|
||||||
|
|
||||||
#### spinor.bin
|
#### 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.
|
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.
|
||||||
|
|
|
@ -5,11 +5,11 @@ These images make the build of the firmware and the generation of the DFU file f
|
||||||
|
|
||||||
Based on Ubuntu 22.04 with the following build dependencies:
|
Based on Ubuntu 22.04 with the following build dependencies:
|
||||||
|
|
||||||
* ARM GCC Toolchain
|
- ARM GCC Toolchain
|
||||||
* nRF SDK
|
- nRF SDK
|
||||||
* MCUBoot
|
- MCUBoot
|
||||||
* adafruit-nrfutil
|
- adafruit-nrfutil
|
||||||
* lv_font_conv
|
- lv_font_conv
|
||||||
|
|
||||||
## Run a container to build the project
|
## Run a container to build the project
|
||||||
|
|
||||||
|
@ -50,9 +50,9 @@ docker run --rm -it -v ${PWD}:/sources --user $(id -u):$(id -g) infinitime/infin
|
||||||
|
|
||||||
The default `latest` tag *should* automatically identify the correct image architecture, but if for some reason Docker does not, you can specify it manually:
|
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
|
## Build the image
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,6 @@ We leverage a few VS Code extensions for ease of development.
|
||||||
|
|
||||||
Cortex-Debug is only required for interactive debugging using VS Codes built in GDB support.
|
Cortex-Debug is only required for interactive debugging using VS Codes built in GDB support.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## VS Code/Docker DevContainer
|
## VS Code/Docker DevContainer
|
||||||
|
|
||||||
The .devcontainer folder contains the configuration and scripts for using a Docker dev container for building InfiniTime
|
The .devcontainer folder contains the configuration and scripts for using a Docker dev container for building InfiniTime
|
||||||
|
@ -37,16 +35,13 @@ Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemNam
|
||||||
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
|
### DevContainer on Ubuntu
|
||||||
|
|
||||||
To use the DevContainer configuration on Ubuntu based systems two changes need to be made:
|
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:
|
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"],
|
`"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:
|
||||||
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",`
|
||||||
``"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:
|
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``.
|
`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.
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Apps
|
# Apps
|
||||||
|
|
||||||
This page will teach you:
|
This page will teach you:
|
||||||
|
|
||||||
- what screens and apps are in InfiniTime
|
- what screens and apps are in InfiniTime
|
||||||
- how to implement your own app
|
- 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.
|
By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected.
|
||||||
|
|
||||||
## Interface
|
## Interface
|
||||||
|
|
||||||
Every app class has to be inside the namespace `Pinetime::Applications::Screens` and inherit from `Screen`.
|
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.
|
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.
|
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 tou
|
||||||
If you have any doubts, you can always look at how the other apps function for reference.
|
If you have any doubts, you can always look at how the other apps function for reference.
|
||||||
|
|
||||||
### Continuous updating
|
### Continuous updating
|
||||||
|
|
||||||
If your app needs to be updated continuously, you can do so by overriding the `Refresh()` function in your class
|
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.
|
and calling `lv_task_create` inside the constructor.
|
||||||
|
|
||||||
An example call could look like this:
|
An example call could look like this:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
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.
|
The function `RefreshTaskCallback` is inherited from `Screen` and just calls your `Refresh` function.
|
||||||
|
|
||||||
## Creating your own app
|
## Creating your own app
|
||||||
|
|
||||||
A minimal app could look like this:
|
A minimal app could look like this:
|
||||||
|
|
||||||
MyApp.h:
|
MyApp.h:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -60,6 +67,7 @@ namespace Pinetime {
|
||||||
```
|
```
|
||||||
|
|
||||||
MyApp.cpp:
|
MyApp.cpp:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include "displayapp/screens/MyApp.h"
|
#include "displayapp/screens/MyApp.h"
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
|
@ -77,6 +85,7 @@ MyApp::~MyApp() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Both of these files should be in [displayapp/screens/](/src/displayapp/screens/)
|
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.
|
or [displayapp/screens/settings/](/src/displayapp/screens/settings/) if it's a setting app.
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Introduction to the code
|
# 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.
|
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
|
## FreeRTOS
|
||||||
|
|
||||||
Infinitime is based on FreeRTOS, a real-time operating system.
|
Infinitime is based on FreeRTOS, a real-time operating system.
|
||||||
FreeRTOS provides several quality of life abstractions (for example easy software timers)
|
FreeRTOS provides several quality of life abstractions (for example easy software timers)
|
||||||
and most importantly supports multiple tasks.
|
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.
|
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
|
||||||
|
|
||||||
Tasks are created by calling `xTaskCreate` and passing a function with the signature `void functionName(void*)`.
|
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).
|
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**.
|
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.
|
You can use `configMINIMAL_STACK_SIZE` which is currently set to 120 words.
|
||||||
|
|
||||||
## Controllers
|
## Controllers
|
||||||
|
|
||||||
Controllers in InfiniTime are singleton objects that can provide access to certain resources to apps.
|
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.
|
Some of them interface with drivers, others are the driver for the resource.
|
||||||
The resources provided don't have to be hardware-based.
|
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 reso
|
||||||
They reside in [components/](/src/components/) inside their own subfolder.
|
They reside in [components/](/src/components/) inside their own subfolder.
|
||||||
|
|
||||||
## Apps
|
## Apps
|
||||||
|
|
||||||
For more detail see the [Apps page](./Apps.md)
|
For more detail see the [Apps page](./Apps.md)
|
||||||
|
|
||||||
## Bluetooth
|
## 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/).
|
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/).
|
||||||
|
|
|
@ -1,41 +1,29 @@
|
||||||
# Coding convention
|
# Coding style
|
||||||
|
|
||||||
## Language
|
## Use these tools to find and fix issues.
|
||||||
|
|
||||||
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.
|
- Use `clang-format` to format the code.
|
||||||
|
- Use `clang-tidy` to check the code for other potential issues.
|
||||||
|
|
||||||
C code is accepted if it comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
## Follow these guidelines while writing code.
|
||||||
|
|
||||||
## Coding style
|
|
||||||
|
|
||||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
|
||||||
|
|
||||||
Using an autoformatter is highly recommended, but make sure it's configured properly.
|
|
||||||
|
|
||||||
There are preconfigured autoformatter rules for:
|
|
||||||
|
|
||||||
* CLion (IntelliJ) in [.idea/codeStyles/Project.xml](/.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
|
- **Indentation** : 2 spaces, no tabulation
|
||||||
- **Opening brace** at the end of the line
|
- **Opening brace** at the end of the line
|
||||||
- **Naming** : Choose self-describing variable name
|
- **Naming** : Choose self-describing variable name
|
||||||
- **class** : PascalCase
|
- **class** : PascalCase
|
||||||
- **namespace** : PascalCase
|
- **namespace** : PascalCase
|
||||||
- **variable** : camelCase, **no** prefix/suffix ('_', 'm_',...) for class members
|
- **variable** : camelCase, **no** prefix/suffix (`_`, `m_`,...) for class members
|
||||||
- **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`)
|
- **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`)
|
||||||
- **Includes** :
|
- **Includes** :
|
||||||
- files from the project : `#include "relative/path/to/the/file.h"`
|
- files from the project : `#include "relative/path/to/the/file.h"`
|
||||||
- external files and std : `#include <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"`
|
- 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)
|
- 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.
|
- 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:
|
```c++
|
||||||
- `auto* app = static_cast<DisplayApp*>(instance);`
|
// Examples:
|
||||||
- `auto number = static_cast<uint8_t>(variable);`
|
auto* app = static_cast<DisplayApp*>(instance);
|
||||||
- `uint8_t returnValue = MyFunction();`
|
auto number = static_cast<uint8_t>(variable);
|
||||||
- Use nullptr instead of NULL
|
uint8_t returnValue = MyFunction();
|
||||||
|
```
|
||||||
|
- Use `nullptr` instead of `NULL`
|
||||||
|
|
|
@ -1,61 +1,19 @@
|
||||||
# How to contribute?
|
# How to contribute?
|
||||||
|
|
||||||
## Report bugs
|
- [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
|
||||||
|
|
||||||
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...
|
## How to create a pull request?
|
||||||
|
|
||||||
## Write and improve documentation
|
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
|
||||||
Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, photo, video,...
|
2. Make changes in this branch
|
||||||
|
- Write code that satisfies the [coding conventions](/doc/coding-convention.md)
|
||||||
As the documentation is part of the source code, you can submit your improvements to the documentation by submitting a pull request (see below).
|
- 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
|
||||||
## 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?
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
|
|
||||||
- Create a branch from develop
|
|
||||||
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...)
|
|
||||||
- Test your modifications on the actual hardware
|
|
||||||
- Check 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 :)
|
|
||||||
|
|
||||||
Your contributions are more than welcome!
|
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.
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Using the releases
|
# 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.
|
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.
|
This page describes the files from the release notes and how to use them.
|
||||||
|
@ -8,6 +9,7 @@ This page describes the files from the release notes and how to use them.
|
||||||
## Files included in the release notes
|
## Files included in the release notes
|
||||||
|
|
||||||
### Standalone firmware
|
### 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.
|
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.out** : Output file of GCC containing debug symbols, useful if you want to debug the firmware using GDB.
|
||||||
|
@ -18,14 +20,15 @@ This firmware is standalone, meaning that it does not need a bootloader to actua
|
||||||
**This firmware must be flashed at address 0x00 in the main flash memory**
|
**This firmware must be flashed at address 0x00 in the main flash memory**
|
||||||
|
|
||||||
### Bootloader
|
### Bootloader
|
||||||
|
|
||||||
The bootloader is maintained by [lupyuen](https://github.com/lupyuen) and is a binary version of [this release](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4).
|
The bootloader is maintained by [lupyuen](https://github.com/lupyuen) and is a binary version of [this release](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4).
|
||||||
|
|
||||||
- **bootloader.hex** : Firmware in Intel HEX file format.
|
- **bootloader.hex** : Firmware in Intel HEX file format.
|
||||||
|
|
||||||
**This firmware must be flashed at address 0x00 in the main flash memory**
|
**This firmware must be flashed at address 0x00 in the main flash memory**
|
||||||
|
|
||||||
|
|
||||||
### 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).
|
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.out** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB.
|
||||||
|
@ -36,6 +39,7 @@ This firmware is a small utility firmware that writes the boot graphic in the ex
|
||||||
**This firmware must be flashed at address 0x00 in the main flash memory**
|
**This firmware must be flashed at address 0x00 in the main flash memory**
|
||||||
|
|
||||||
### Firmware with bootloader
|
### Firmware with bootloader
|
||||||
|
|
||||||
This firmware is intended to be used with our [MCUBoot-based bootloader](../bootloader/README.md).
|
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.
|
||||||
|
@ -48,9 +52,9 @@ The following files are not directly usable by the bootloader:
|
||||||
- **pinetime-mcuboot-app.map** : Map file containing all the symbols, addresses in memory,...
|
- **pinetime-mcuboot-app.map** : Map file containing all the symbols, addresses in memory,...
|
||||||
|
|
||||||
### OTA (Update the firmware Over-The-Air)
|
### 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**.
|
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 !
|
**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.
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ run
|
||||||
```
|
```
|
||||||
|
|
||||||
Example :
|
Example :
|
||||||
|
|
||||||
```
|
```
|
||||||
$ /home/jf/nrf52/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-gdb
|
$ /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
|
Start address 0x0, load size 314200
|
||||||
Transfer rate: 45 KB/sec, 969 bytes/write.
|
Transfer rate: 45 KB/sec, 969 bytes/write.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -19,4 +19,5 @@ Don't forget to **validate** your firmware. In the InfiniTime go to the settings
|
||||||
![NRFConnect 3](nrfconnect3.jpg)
|
![NRFConnect 3](nrfconnect3.jpg)
|
||||||
|
|
||||||
# Demo
|
# Demo
|
||||||
|
|
||||||
[This video](https://seafile.codingfield.com/f/a52b69683a05472a90c7/) shows how to use NRFConnect to update the firmware running on the Pinetime.
|
[This video](https://seafile.codingfield.com/f/a52b69683a05472a90c7/) shows how to use NRFConnect to update the firmware running on the Pinetime.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Flashing the firmware with JLink
|
# Flashing the firmware with JLink
|
||||||
|
|
||||||
Start JLinkExe:
|
Start JLinkExe:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ /opt/SEGGER/JLink/JLinkExe -device nrf52 -if swd -speed 4000 -autoconnect 1
|
$ /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)
|
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:
|
Use the command loadfile to program the .hex file:
|
||||||
|
|
||||||
```
|
```
|
||||||
J-Link>loadfile pinetime-app.hex
|
J-Link>loadfile pinetime-app.hex
|
||||||
Downloading file [pinetime-app.hex]...
|
Downloading file [pinetime-app.hex]...
|
||||||
|
@ -56,6 +58,7 @@ O.K.
|
||||||
```
|
```
|
||||||
|
|
||||||
Then reset (r) and start (g) the CPU:
|
Then reset (r) and start (g) the CPU:
|
||||||
|
|
||||||
```
|
```
|
||||||
J-Link>r
|
J-Link>r
|
||||||
Reset delay: 0 ms
|
Reset delay: 0 ms
|
||||||
|
@ -66,6 +69,7 @@ J-Link>g
|
||||||
```
|
```
|
||||||
|
|
||||||
# JLink RTT
|
# 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.
|
RTT is a feature from Segger's JLink devices that allows bidirectional communication between the debugger and the target. This feature can be used to get the logs from the embedded software on the development computer.
|
||||||
|
|
||||||
- Program the MCU with the code (see above)
|
- Program the MCU with the code (see above)
|
||||||
|
@ -76,7 +80,7 @@ $ JLinkExe -device nrf52 -if swd -speed 4000 -autoconnect 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Start JLinkRTTClient
|
Start JLinkRTTClient
|
||||||
|
|
||||||
```
|
```
|
||||||
$ JLinkRTTClient
|
$ JLinkRTTClient
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
@ -1,4 +1,5 @@
|
||||||
# OpenOCD and STLink
|
# 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 (**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.
|
OpenOCD supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger.
|
||||||
|
@ -6,6 +7,7 @@ OpenOCD supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a
|
||||||
OpenOCD works on X86 computers, ARM/ARM64 computers, and SBCs (like the RaspberryPi and Pine64 Pinebook Pro)!
|
OpenOCD works on X86 computers, ARM/ARM64 computers, and SBCs (like the RaspberryPi and Pine64 Pinebook Pro)!
|
||||||
|
|
||||||
## Installation
|
## 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.
|
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:
|
||||||
|
@ -22,6 +24,7 @@ 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 cp contrib/60-openocd.rules /etc/udev/rules.d/
|
||||||
sudo udevadm control --reload-rules
|
sudo udevadm control --reload-rules
|
||||||
|
@ -50,11 +53,14 @@ Info : STLINK V2J34S7 (API v2) VID:PID 0483:3748
|
||||||
Info : Target voltage: 3.294340
|
Info : Target voltage: 3.294340
|
||||||
Error: init mode failed (unable to connect to the target)
|
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.
|
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
|
## Configuration files
|
||||||
|
|
||||||
OpenOCD is configured using configuration files.
|
OpenOCD is configured using configuration files.
|
||||||
First, we need a common configuration file for the project : **openocd-stlink.ocd**:
|
First, we need a common configuration file for the project : **openocd-stlink.ocd**:
|
||||||
|
|
||||||
```
|
```
|
||||||
source [find interface/stlink.cfg]
|
source [find interface/stlink.cfg]
|
||||||
|
|
||||||
|
@ -63,11 +69,13 @@ gdb_breakpoint_override hard
|
||||||
|
|
||||||
source [find target/nrf52.cfg]
|
source [find target/nrf52.cfg]
|
||||||
```
|
```
|
||||||
|
|
||||||
This file specifies to OpenOCD which debugger and target it will be connected to.
|
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.
|
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**:
|
This files flashes the bootloader and the application firmware : **flash_bootloader_app.ocd**:
|
||||||
|
|
||||||
```
|
```
|
||||||
init
|
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**:
|
And this one flashes the graphics flasher (it writes the bootloader graphics into the SPI NOR flash memory) : **flash_graphics.ocd**:
|
||||||
|
|
||||||
```
|
```
|
||||||
init
|
init
|
||||||
|
|
||||||
|
@ -87,19 +96,23 @@ reset
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Flash bootloader and application
|
### Flash bootloader and application
|
||||||
|
|
||||||
```
|
```
|
||||||
openocd -f ./openocd-stlink.ocd -f ./flash_bootloader_app.ocd
|
openocd -f ./openocd-stlink.ocd -f ./flash_bootloader_app.ocd
|
||||||
```
|
```
|
||||||
|
|
||||||
### Flash graphics flasher
|
### Flash graphics flasher
|
||||||
|
|
||||||
```
|
```
|
||||||
openocd -f ./openocd-stlink.ocd -f ./flash_graphics.ocd
|
openocd -f ./openocd-stlink.ocd -f ./flash_graphics.ocd
|
||||||
```
|
```
|
||||||
|
|
||||||
## Connect the STLinkV2 to the PineTime
|
## Connect the STLinkV2 to the PineTime
|
||||||
|
|
||||||
Here is an example using the pogo pins:
|
Here is an example using the pogo pins:
|
||||||
![SWD pinout](../images/swd_pinout.jpg)
|
![SWD pinout](openOCD/swd_pinout.jpg)
|
||||||
![Pogo pins](../images/pogopins.jpg)
|
![Pogo pins](openOCD/pogopins.jpg)
|
||||||
|
|
||||||
You can find more information about the SWD wiring [on the wiki](https://wiki.pine64.org/index.php?title=PineTime_devkit_wiring).
|
You can find more information about the SWD wiring [on the wiki](https://wiki.pine64.org/index.php?title=PineTime_devkit_wiring).
|
||||||
|
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
@ -1,4 +1,5 @@
|
||||||
# Versioning
|
# Versioning
|
||||||
|
|
||||||
The versioning of this project is based on [Semantic versioning](https://semver.org/):
|
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 **patch** is incremented when a bug is fixed on a **released** version (most of the time using a **hotfix** branch).
|
||||||
|
|
Before Width: | Height: | Size: 607 KiB |
Before Width: | Height: | Size: 625 KiB |
Before Width: | Height: | Size: 576 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 2 MiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 2.7 MiB |
Before Width: | Height: | Size: 1.8 MiB |
Before Width: | Height: | Size: 2.3 MiB |
Before Width: | Height: | Size: 2.3 MiB |
|
@ -477,7 +477,7 @@ list(APPEND SOURCE_FILES
|
||||||
FreeRTOS/port_cmsis.c
|
FreeRTOS/port_cmsis.c
|
||||||
|
|
||||||
displayapp/LittleVgl.cpp
|
displayapp/LittleVgl.cpp
|
||||||
displayapp/lv_pinetime_theme.c
|
displayapp/InfiniTimeTheme.cpp
|
||||||
|
|
||||||
systemtask/SystemTask.cpp
|
systemtask/SystemTask.cpp
|
||||||
systemtask/SystemMonitor.cpp
|
systemtask/SystemMonitor.cpp
|
||||||
|
@ -663,7 +663,7 @@ set(INCLUDE_FILES
|
||||||
libs/date/include/date/ptz.h
|
libs/date/include/date/ptz.h
|
||||||
libs/date/include/date/tz_private.h
|
libs/date/include/date/tz_private.h
|
||||||
displayapp/LittleVgl.h
|
displayapp/LittleVgl.h
|
||||||
displayapp/lv_pinetime_theme.h
|
displayapp/InfiniTimeTheme.h
|
||||||
systemtask/SystemTask.h
|
systemtask/SystemTask.h
|
||||||
systemtask/SystemMonitor.h
|
systemtask/SystemMonitor.h
|
||||||
displayapp/screens/Symbols.h
|
displayapp/screens/Symbols.h
|
||||||
|
@ -810,6 +810,7 @@ elseif(TARGET_DEVICE STREQUAL "MOY-UNK") # P8b mirrored
|
||||||
add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC
|
add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC
|
||||||
add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500)
|
add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500)
|
||||||
add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1)
|
add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1)
|
||||||
|
add_definitions(-DDRIVER_DISPLAY_MIRROR)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Invalid TARGET_DEVICE")
|
message(FATAL_ERROR "Invalid TARGET_DEVICE")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Pinetime {
|
||||||
class Settings {
|
class Settings {
|
||||||
public:
|
public:
|
||||||
enum class ClockType : uint8_t { H24, H12 };
|
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 ChimesOption : uint8_t { None, Hours, HalfHours };
|
||||||
enum class WakeUpMode : uint8_t {
|
enum class WakeUpMode : uint8_t {
|
||||||
SingleTap = 0,
|
SingleTap = 0,
|
||||||
|
@ -219,7 +219,7 @@ namespace Pinetime {
|
||||||
uint32_t screenTimeOut = 15000;
|
uint32_t screenTimeOut = 15000;
|
||||||
|
|
||||||
ClockType clockType = ClockType::H24;
|
ClockType clockType = ClockType::H24;
|
||||||
Notification notificationStatus = Notification::ON;
|
Notification notificationStatus = Notification::On;
|
||||||
|
|
||||||
uint8_t clockFace = 0;
|
uint8_t clockFace = 0;
|
||||||
ChimesOption chimesOption = ChimesOption::None;
|
ChimesOption chimesOption = ChimesOption::None;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "displayapp/lv_pinetime_theme.h"
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name);
|
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name);
|
||||||
|
|
||||||
|
@ -31,13 +31,14 @@ static lv_style_t style_cb_bullet;
|
||||||
static bool inited;
|
static bool inited;
|
||||||
|
|
||||||
static void style_init_reset(lv_style_t* style) {
|
static void style_init_reset(lv_style_t* style) {
|
||||||
if (inited)
|
if (inited) {
|
||||||
lv_style_reset(style);
|
lv_style_reset(style);
|
||||||
else
|
} else {
|
||||||
lv_style_init(style);
|
lv_style_init(style);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void basic_init(void) {
|
static void basic_init() {
|
||||||
style_init_reset(&style_bg);
|
style_init_reset(&style_bg);
|
||||||
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
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_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||||
|
@ -46,7 +47,7 @@ static void basic_init(void) {
|
||||||
style_init_reset(&style_box);
|
style_init_reset(&style_box);
|
||||||
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
|
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_radius(&style_box, LV_STATE_DEFAULT, 10);
|
||||||
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, IT_COLOR_BG);
|
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);
|
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
|
||||||
|
|
||||||
style_init_reset(&style_label_white);
|
style_init_reset(&style_label_white);
|
||||||
|
@ -56,9 +57,9 @@ static void basic_init(void) {
|
||||||
style_init_reset(&style_btn);
|
style_init_reset(&style_btn);
|
||||||
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
|
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_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_DEFAULT, Colors::bg);
|
||||||
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, IT_COLOR_SEL);
|
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, Colors::highlight);
|
||||||
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, IT_COLOR_BG_DARK);
|
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_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||||
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
|
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
|
||||||
|
|
||||||
|
@ -96,9 +97,9 @@ static void basic_init(void) {
|
||||||
style_init_reset(&style_list_btn);
|
style_init_reset(&style_list_btn);
|
||||||
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
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_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_DEFAULT, Colors::bg);
|
||||||
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
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_DEFAULT, Colors::bg);
|
||||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
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_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_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
|
||||||
|
@ -110,21 +111,21 @@ static void basic_init(void) {
|
||||||
// Causes lag unfortunately, so we'll have to live with the selected item overflowing the corner
|
// 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_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_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_bg_color(&style_ddlist_list, LV_STATE_DEFAULT, Colors::lightGray);
|
||||||
lv_style_set_pad_all(&style_ddlist_list, LV_STATE_DEFAULT, 20);
|
lv_style_set_pad_all(&style_ddlist_list, LV_STATE_DEFAULT, 20);
|
||||||
|
|
||||||
style_init_reset(&style_ddlist_selected);
|
style_init_reset(&style_ddlist_selected);
|
||||||
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
|
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);
|
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, Colors::bg);
|
||||||
|
|
||||||
style_init_reset(&style_sw_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_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_bg_color(&style_sw_bg, LV_STATE_DEFAULT, Colors::bg);
|
||||||
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||||
|
|
||||||
style_init_reset(&style_sw_indic);
|
style_init_reset(&style_sw_indic);
|
||||||
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
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);
|
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, Colors::highlight);
|
||||||
|
|
||||||
style_init_reset(&style_sw_knob);
|
style_init_reset(&style_sw_knob);
|
||||||
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||||
|
@ -152,12 +153,12 @@ static void basic_init(void) {
|
||||||
lv_style_set_pad_right(&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);
|
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_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_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
|
||||||
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
|
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
|
||||||
|
|
||||||
style_init_reset(&style_arc_bg);
|
style_init_reset(&style_arc_bg);
|
||||||
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, IT_COLOR_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_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_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_set_pad_all(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(5));
|
||||||
|
@ -215,8 +216,8 @@ static void basic_init(void) {
|
||||||
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
|
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
|
||||||
|
|
||||||
lv_style_reset(&style_cb_bullet);
|
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_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_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_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_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||||
|
@ -262,9 +263,7 @@ lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||||
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
||||||
lv_style_list_t* list;
|
lv_style_list_t* list;
|
||||||
|
|
||||||
/*To avoid warnings*/
|
switch (name) {
|
||||||
uint32_t name_int = (uint32_t) name;
|
|
||||||
switch (name_int) {
|
|
||||||
case LV_THEME_NONE:
|
case LV_THEME_NONE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -402,7 +401,7 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
||||||
_lv_style_list_add_style(list, &style_scrollbar);
|
_lv_style_list_add_style(list, &style_scrollbar);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LV_THEME_TABLE:
|
case LV_THEME_TABLE: {
|
||||||
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
|
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
|
||||||
_lv_style_list_add_style(list, &style_bg);
|
_lv_style_list_add_style(list, &style_bg);
|
||||||
|
|
||||||
|
@ -415,7 +414,7 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
||||||
_lv_style_list_add_style(list, &style_table_cell);
|
_lv_style_list_add_style(list, &style_table_cell);
|
||||||
_lv_style_list_add_style(list, &style_label_white);
|
_lv_style_list_add_style(list, &style_label_white);
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
case LV_THEME_LINEMETER:
|
case LV_THEME_LINEMETER:
|
||||||
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
|
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
|
|
@ -1,14 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
|
|
||||||
#define IT_COLOR_BG LV_COLOR_MAKE(0x5d, 0x69, 0x7e)
|
namespace Colors {
|
||||||
#define IT_COLOR_BG_DARK LV_COLOR_MAKE(0x18, 0x18, 0x18)
|
static constexpr lv_color_t orange = LV_COLOR_MAKE(0xff, 0xb0, 0x0);
|
||||||
#define IT_COLOR_SEL LV_COLOR_MAKE(0x0, 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
|
* Initialize the default
|
||||||
|
@ -28,6 +31,3 @@ lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||||
const lv_font_t* font_normal,
|
const lv_font_t* font_normal,
|
||||||
const lv_font_t* font_subtitle,
|
const lv_font_t* font_subtitle,
|
||||||
const lv_font_t* font_title);
|
const lv_font_t* font_title);
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "displayapp/LittleVgl.h"
|
#include "displayapp/LittleVgl.h"
|
||||||
#include "displayapp/lv_pinetime_theme.h"
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
#include <task.h>
|
#include <task.h>
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
# Fonts
|
# Fonts
|
||||||
|
|
||||||
* [Jetbrains Mono](https://www.jetbrains.com/lp/mono/)
|
- [Jetbrains Mono](https://www.jetbrains.com/lp/mono/)
|
||||||
* [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid)
|
- [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid)
|
||||||
* [Open Sans Light](https://fonts.google.com/specimen/Open+Sans)
|
- [Open Sans Light](https://fonts.google.com/specimen/Open+Sans)
|
||||||
* [Material Symbols](https://fonts.google.com/icons)
|
- [Material Symbols](https://fonts.google.com/icons)
|
||||||
|
|
||||||
### How to add new symbols:
|
### How to add new symbols:
|
||||||
|
|
||||||
* Browse the cheat sheets and pick symbols
|
- Browse the cheat sheets and pick symbols
|
||||||
* [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid)
|
- [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid)
|
||||||
* [Material Symbols](https://fonts.google.com/icons)
|
- [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
|
- 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
|
- 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)
|
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";
|
static constexpr const char* newSymbol = "\xEF\x86\x85";
|
||||||
|
@ -23,13 +23,13 @@ static constexpr const char* newSymbol = "\xEF\x86\x85";
|
||||||
|
|
||||||
inside `fonts`, there is a dictionary of fonts,
|
inside `fonts`, there is a dictionary of fonts,
|
||||||
and for each font there is:
|
and for each font there is:
|
||||||
* sources - list of file,range(,symbols) wanted (as a dictionary of those)
|
|
||||||
* bpp - bits per pixel.
|
- sources - list of file,range(,symbols) wanted (as a dictionary of those)
|
||||||
* size - size.
|
- bpp - bits per pixel.
|
||||||
* patches - list of extra "patches" to run: a path to a .patch file. (may be relative)
|
- size - size.
|
||||||
* compress - optional. default disabled. add `"compress": true` to enable
|
- 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
|
### 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.
|
`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.
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "FontAwesome5-Solid+Brands+Regular.woff",
|
"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,
|
"bpp": 1,
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"file": "material-design-icons/MaterialIcons-Regular.ttf",
|
"file": "material-design-icons/MaterialIcons-Regular.ttf",
|
||||||
"range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8, 0xe40a"
|
"range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8, 0xef44, 0xe40a"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"bpp": 1,
|
"bpp": 1,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "displayapp/screens/Alarm.h"
|
#include "displayapp/screens/Alarm.h"
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
using Pinetime::Controllers::AlarmController;
|
using Pinetime::Controllers::AlarmController;
|
||||||
|
@ -79,7 +80,7 @@ Alarm::Alarm(DisplayApp* app,
|
||||||
lv_label_set_text_static(txtStop, Symbols::stop);
|
lv_label_set_text_static(txtStop, Symbols::stop);
|
||||||
lv_obj_set_hidden(btnStop, true);
|
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 = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnRecur->user_data = this;
|
btnRecur->user_data = this;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "displayapp/screens/BatteryInfo.h"
|
#include "displayapp/screens/BatteryInfo.h"
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "components/battery/BatteryController.h"
|
#include "components/battery/BatteryController.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -16,9 +17,9 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
|
||||||
lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
|
lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
|
||||||
lv_bar_set_anim_time(charging_bar, 1000);
|
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_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_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);
|
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
|
||||||
|
|
||||||
status = lv_label_create(lv_scr_act(), nullptr);
|
status = lv_label_create(lv_scr_act(), nullptr);
|
||||||
|
@ -33,7 +34,7 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
|
||||||
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
|
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
|
||||||
|
|
||||||
voltage = lv_label_create(lv_scr_act(), nullptr);
|
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_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
|
||||||
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
|
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
|
||||||
|
@ -62,7 +63,7 @@ void BatteryInfo::Refresh() {
|
||||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
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");
|
lv_label_set_text_static(status, "Battery low");
|
||||||
} else {
|
} 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");
|
lv_label_set_text_static(status, "Discharging");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "components/firmwarevalidator/FirmwareValidator.h"
|
#include "components/firmwarevalidator/FirmwareValidator.h"
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app,
|
||||||
lv_obj_set_size(buttonValidate, 115, 50);
|
lv_obj_set_size(buttonValidate, 115, 50);
|
||||||
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
lv_obj_set_event_cb(buttonValidate, ButtonEventHandler);
|
lv_obj_set_event_cb(buttonValidate, ButtonEventHandler);
|
||||||
lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_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);
|
labelButtonValidate = lv_label_create(buttonValidate, nullptr);
|
||||||
lv_label_set_text_static(labelButtonValidate, "Validate");
|
lv_label_set_text_static(labelButtonValidate, "Validate");
|
||||||
|
@ -51,7 +52,7 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app,
|
||||||
buttonReset->user_data = this;
|
buttonReset->user_data = this;
|
||||||
lv_obj_set_size(buttonReset, 115, 50);
|
lv_obj_set_size(buttonReset, 115, 50);
|
||||||
lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_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);
|
lv_obj_set_event_cb(buttonReset, ButtonEventHandler);
|
||||||
|
|
||||||
labelButtonReset = lv_label_create(buttonReset, nullptr);
|
labelButtonReset = lv_label_create(buttonReset, nullptr);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "displayapp/screens/FlashLight.h"
|
#include "displayapp/screens/FlashLight.h"
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ FlashLight::~FlashLight() {
|
||||||
|
|
||||||
void FlashLight::SetColors() {
|
void FlashLight::SetColors() {
|
||||||
lv_color_t bgColor = isOn ? LV_COLOR_WHITE : LV_COLOR_BLACK;
|
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_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);
|
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fgColor);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <components/heartrate/HeartRateController.h>
|
#include <components/heartrate/HeartRateController.h>
|
||||||
|
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -36,10 +37,11 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
|
||||||
|
|
||||||
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||||
|
|
||||||
if (isHrRunning)
|
if (isHrRunning) {
|
||||||
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
|
} else {
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
lv_label_set_text_static(label_hr, "000");
|
lv_label_set_text_static(label_hr, "000");
|
||||||
lv_obj_align(label_hr, nullptr, LV_ALIGN_CENTER, 0, -40);
|
lv_obj_align(label_hr, nullptr, LV_ALIGN_CENTER, 0, -40);
|
||||||
|
@ -97,12 +99,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
|
||||||
heartRateController.Start();
|
heartRateController.Start();
|
||||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
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 {
|
} else {
|
||||||
heartRateController.Stop();
|
heartRateController.Stop();
|
||||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "displayapp/screens/InfiniPaint.h"
|
#include "displayapp/screens/InfiniPaint.h"
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/LittleVgl.h"
|
#include "displayapp/LittleVgl.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
#include <algorithm> // std::fill
|
#include <algorithm> // std::fill
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||||
selectColor = LV_COLOR_MAGENTA;
|
selectColor = LV_COLOR_MAGENTA;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
selectColor = LV_COLOR_MAKE(0x0, 0xb0, 0x0);
|
selectColor = Colors::green;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
selectColor = LV_COLOR_WHITE;
|
selectColor = LV_COLOR_WHITE;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "displayapp/screens/Metronome.h"
|
#include "displayapp/screens/Metronome.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ namespace {
|
||||||
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* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x, uint8_t y) {
|
||||||
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
|
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
|
||||||
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_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_label_set_text(label, name);
|
||||||
lv_obj_align(label, reference, align, x, y);
|
lv_obj_align(label, reference, align, x, y);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "displayapp/screens/Motion.h"
|
#include "displayapp/screens/Motion.h"
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr
|
||||||
|
|
||||||
/*Add 3 data series*/
|
/*Add 3 data series*/
|
||||||
ser1 = lv_chart_add_series(chart, LV_COLOR_RED);
|
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);
|
ser3 = lv_chart_add_series(chart, LV_COLOR_YELLOW);
|
||||||
|
|
||||||
lv_chart_init_points(chart, ser1, 0);
|
lv_chart_init_points(chart, ser1, 0);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "components/ble/NavigationService.h"
|
#include "components/ble/NavigationService.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -192,7 +193,7 @@ void Navigation::Refresh() {
|
||||||
if (progress > 90) {
|
if (progress > 90) {
|
||||||
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "components/ble/AlertNotificationService.h"
|
#include "components/ble/AlertNotificationService.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
extern lv_font_t jetbrains_mono_extrabold_compressed;
|
extern lv_font_t jetbrains_mono_extrabold_compressed;
|
||||||
|
@ -257,7 +258,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||||
lv_obj_set_style_local_border_width(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);
|
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_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_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);
|
lv_obj_set_style_local_border_width(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
@ -272,7 +273,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||||
lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16);
|
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_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(0xb0, 0xb0, 0xb0));
|
lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
|
||||||
if (title == nullptr) {
|
if (title == nullptr) {
|
||||||
lv_label_set_text_static(alert_type, "Notification");
|
lv_label_set_text_static(alert_type, "Notification");
|
||||||
} else {
|
} else {
|
||||||
|
@ -289,21 +290,16 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||||
lv_obj_set_width(alert_type, 180);
|
lv_obj_set_width(alert_type, 180);
|
||||||
lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16);
|
lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16);
|
||||||
|
|
||||||
/////////
|
|
||||||
switch (category) {
|
|
||||||
default: {
|
|
||||||
lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr);
|
lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr);
|
||||||
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
|
|
||||||
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
||||||
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
||||||
|
|
||||||
|
switch (category) {
|
||||||
|
default:
|
||||||
lv_label_set_text(alert_subject, msg);
|
lv_label_set_text(alert_subject, msg);
|
||||||
} break;
|
break;
|
||||||
case Controllers::NotificationManager::Categories::IncomingCall: {
|
case Controllers::NotificationManager::Categories::IncomingCall: {
|
||||||
lv_obj_set_height(subject_container, 108);
|
lv_obj_set_height(subject_container, 108);
|
||||||
lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr);
|
|
||||||
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
|
|
||||||
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
|
||||||
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
|
||||||
lv_label_set_text_static(alert_subject, "Incoming call from");
|
lv_label_set_text_static(alert_subject, "Incoming call from");
|
||||||
|
|
||||||
lv_obj_t* alert_caller = lv_label_create(subject_container, nullptr);
|
lv_obj_t* alert_caller = lv_label_create(subject_container, nullptr);
|
||||||
|
@ -319,7 +315,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||||
lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||||
label_accept = lv_label_create(bt_accept, nullptr);
|
label_accept = lv_label_create(bt_accept, nullptr);
|
||||||
lv_label_set_text_static(label_accept, Symbols::phone);
|
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 = lv_btn_create(container, nullptr);
|
||||||
bt_reject->user_data = this;
|
bt_reject->user_data = this;
|
||||||
|
@ -337,7 +333,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||||
lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||||
label_mute = lv_label_create(bt_mute, nullptr);
|
label_mute = lv_label_create(bt_mute, nullptr);
|
||||||
lv_label_set_text_static(label_mute, Symbols::volumMute);
|
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;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
PassKey::PassKey(Pinetime::Applications::DisplayApp* app, uint32_t key) : Screen(app) {
|
PassKey::PassKey(Pinetime::Applications::DisplayApp* app, uint32_t key) : Screen(app) {
|
||||||
passkeyLabel = lv_label_create(lv_scr_act(), nullptr);
|
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_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_label_set_text_fmt(passkeyLabel, "%06u", key);
|
||||||
lv_obj_align(passkeyLabel, nullptr, LV_ALIGN_CENTER, 0, -20);
|
lv_obj_align(passkeyLabel, nullptr, LV_ALIGN_CENTER, 0, -20);
|
||||||
|
|
|
@ -20,7 +20,7 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
|
||||||
lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
|
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_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_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_arc_set_end_angle(stepsArc, 200);
|
||||||
lv_obj_set_size(stepsArc, 240, 240);
|
lv_obj_set_size(stepsArc, 240, 240);
|
||||||
lv_arc_set_range(stepsArc, 0, 500);
|
lv_arc_set_range(stepsArc, 0, 500);
|
||||||
|
@ -32,7 +32,7 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
|
||||||
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
|
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
|
||||||
|
|
||||||
lSteps = lv_label_create(lv_scr_act(), nullptr);
|
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_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_label_set_text_fmt(lSteps, "%li", stepsCount);
|
||||||
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -40);
|
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -40);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "displayapp/screens/StopWatch.h"
|
#include "displayapp/screens/StopWatch.h"
|
||||||
|
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -30,13 +31,13 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) : Screen(a
|
||||||
|
|
||||||
time = lv_label_create(lv_scr_act(), nullptr);
|
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_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_label_set_text_static(time, "00:00");
|
||||||
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45);
|
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45);
|
||||||
|
|
||||||
msecTime = lv_label_create(lv_scr_act(), nullptr);
|
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_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_label_set_text_static(msecTime, "00");
|
||||||
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3);
|
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3);
|
||||||
|
|
||||||
|
@ -75,8 +76,8 @@ StopWatch::~StopWatch() {
|
||||||
void StopWatch::Reset() {
|
void StopWatch::Reset() {
|
||||||
currentState = States::Init;
|
currentState = States::Init;
|
||||||
oldTimeElapsed = 0;
|
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(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, 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(time, "00:00");
|
lv_label_set_text_static(time, "00:00");
|
||||||
lv_label_set_text_static(msecTime, "00");
|
lv_label_set_text_static(msecTime, "00");
|
||||||
|
@ -90,8 +91,8 @@ void StopWatch::Reset() {
|
||||||
void StopWatch::Start() {
|
void StopWatch::Start() {
|
||||||
lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT);
|
lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_state(txtStopLap, 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(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, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
|
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(txtPlayPause, Symbols::pause);
|
||||||
lv_label_set_text_static(txtStopLap, Symbols::lapsFlag);
|
lv_label_set_text_static(txtStopLap, Symbols::lapsFlag);
|
||||||
startTime = xTaskGetTickCount();
|
startTime = xTaskGetTickCount();
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "Styles.h"
|
#include "Styles.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
void Pinetime::Applications::Screens::SetRadioButtonStyle(lv_obj_t* checkbox) {
|
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_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_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);
|
lv_obj_set_style_local_bg_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace Pinetime {
|
||||||
static constexpr const char* chartLine = "\xEF\x88\x81";
|
static constexpr const char* chartLine = "\xEF\x88\x81";
|
||||||
static constexpr const char* eye = "\xEF\x81\xAE";
|
static constexpr const char* eye = "\xEF\x81\xAE";
|
||||||
static constexpr const char* home = "\xEF\x80\x95";
|
static constexpr const char* home = "\xEF\x80\x95";
|
||||||
|
static constexpr const char* sleep = "\xEE\xBD\x84";
|
||||||
|
|
||||||
// lv_font_sys_48.c
|
// lv_font_sys_48.c
|
||||||
static constexpr const char* settings = "\xEE\xA2\xB8";
|
static constexpr const char* settings = "\xEE\xA2\xB8";
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "components/datetime/DateTimeController.h"
|
#include "components/datetime/DateTimeController.h"
|
||||||
#include "components/motion/MotionController.h"
|
#include "components/motion/MotionController.h"
|
||||||
#include "drivers/Watchdog.h"
|
#include "drivers/Watchdog.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -218,7 +219,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
|
||||||
lv_table_set_col_cnt(infoTask, 4);
|
lv_table_set_col_cnt(infoTask, 4);
|
||||||
lv_table_set_row_cnt(infoTask, maxTaskCount + 1);
|
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_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_cell_value(infoTask, 0, 0, "#");
|
||||||
lv_table_set_col_width(infoTask, 0, 30);
|
lv_table_set_col_width(infoTask, 0, 30);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/screens/BatteryIcon.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;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ Tile::Tile(uint8_t screenID,
|
||||||
lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_OPA_50);
|
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_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_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_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);
|
lv_obj_set_style_local_pad_inner(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 10);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "displayapp/screens/Timer.h"
|
#include "displayapp/screens/Timer.h"
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
@ -54,7 +55,7 @@ Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) : S
|
||||||
btnPlayPause = lv_btn_create(btnObjectMask, nullptr);
|
btnPlayPause = lv_btn_create(btnObjectMask, nullptr);
|
||||||
btnPlayPause->user_data = this;
|
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_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_event_cb(btnPlayPause, btnEventHandler);
|
||||||
lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50);
|
lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
#include "displayapp/screens/NotificationIcon.h"
|
#include "displayapp/screens/NotificationIcon.h"
|
||||||
#include "components/settings/Settings.h"
|
#include "components/settings/Settings.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
LV_IMG_DECLARE(bg_clock);
|
LV_IMG_DECLARE(bg_clock);
|
||||||
|
|
||||||
|
@ -73,14 +74,14 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
|
||||||
lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||||
|
|
||||||
notificationIcon = lv_label_create(lv_scr_act(), NULL);
|
notificationIcon = lv_label_create(lv_scr_act(), 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_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
|
||||||
lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||||
|
|
||||||
// Date - Day / Week day
|
// Date - Day / Week day
|
||||||
|
|
||||||
label_date_day = lv_label_create(lv_scr_act(), NULL);
|
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_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
|
||||||
lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0);
|
lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0);
|
||||||
|
|
|
@ -34,7 +34,7 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
||||||
statusIcons.Create();
|
statusIcons.Create();
|
||||||
|
|
||||||
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
|
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_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
|
||||||
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||||
|
|
||||||
|
|
|
@ -104,11 +104,11 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
|
||||||
lv_obj_align(plugIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
|
lv_obj_align(plugIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
|
||||||
|
|
||||||
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
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, "");
|
lv_label_set_text_static(bleIcon, "");
|
||||||
|
|
||||||
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
|
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, "");
|
lv_label_set_text_static(notificationIcon, "");
|
||||||
|
|
||||||
// Calendar icon
|
// Calendar icon
|
||||||
|
|
|
@ -2,20 +2,29 @@
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
#include "displayapp/screens/BatteryIcon.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;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
|
void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||||
auto* screen = static_cast<QuickSettings*>(obj->user_data);
|
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) {
|
void lv_update_task(struct _lv_task_t* task) {
|
||||||
auto* user_data = static_cast<QuickSettings*>(task->user_data);
|
auto* user_data = static_cast<QuickSettings*>(task->user_data);
|
||||||
user_data->UpdateScreen();
|
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,
|
QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
|
||||||
|
@ -50,7 +59,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
|
||||||
|
|
||||||
lv_style_init(&btn_style);
|
lv_style_init(&btn_style);
|
||||||
lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, buttonHeight / 4);
|
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 = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btn1->user_data = this;
|
btn1->user_data = this;
|
||||||
|
@ -78,19 +87,24 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
|
||||||
btn3 = lv_btn_create(lv_scr_act(), nullptr);
|
btn3 = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btn3->user_data = this;
|
btn3->user_data = this;
|
||||||
lv_obj_set_event_cb(btn3, ButtonEventHandler);
|
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_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_set_size(btn3, buttonWidth, buttonHeight);
|
||||||
lv_obj_align(btn3, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, buttonXOffset, 0);
|
lv_obj_align(btn3, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, buttonXOffset, 0);
|
||||||
|
|
||||||
btn3_lvl = lv_label_create(btn3, nullptr);
|
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);
|
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) {
|
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) {
|
||||||
lv_obj_add_state(btn3, LV_STATE_CHECKED);
|
|
||||||
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
|
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);
|
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);
|
btn4 = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
|
@ -121,31 +135,33 @@ void QuickSettings::UpdateScreen() {
|
||||||
statusIcons.Update();
|
statusIcons.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
void QuickSettings::OnButtonEvent(lv_obj_t* object) {
|
||||||
if (object == btn2 && event == LV_EVENT_CLICKED) {
|
if (object == btn2) {
|
||||||
|
|
||||||
running = false;
|
|
||||||
app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::Up);
|
app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::Up);
|
||||||
|
} else if (object == btn1) {
|
||||||
} else if (object == btn1 && event == LV_EVENT_CLICKED) {
|
|
||||||
|
|
||||||
brightness.Step();
|
brightness.Step();
|
||||||
lv_label_set_text_static(btn1_lvl, brightness.GetIcon());
|
lv_label_set_text_static(btn1_lvl, brightness.GetIcon());
|
||||||
settingsController.SetBrightness(brightness.Level());
|
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) {
|
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) {
|
||||||
settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON);
|
settingsController.SetNotificationStatus(Controllers::Settings::Notification::Off);
|
||||||
motorController.RunForDuration(35);
|
|
||||||
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
|
|
||||||
} else {
|
|
||||||
settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF);
|
|
||||||
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
|
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) {
|
} else if (object == btn4) {
|
||||||
running = false;
|
|
||||||
settingsController.SetSettingsMenu(0);
|
settingsController.SetSettingsMenu(0);
|
||||||
app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up);
|
app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace Pinetime {
|
||||||
|
|
||||||
~QuickSettings() override;
|
~QuickSettings() override;
|
||||||
|
|
||||||
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
void OnButtonEvent(lv_obj_t* object);
|
||||||
|
|
||||||
void UpdateScreen();
|
void UpdateScreen();
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,36 @@ namespace {
|
||||||
constexpr int16_t POS_X_DAY = -72;
|
constexpr int16_t POS_X_DAY = -72;
|
||||||
constexpr int16_t POS_X_MONTH = 0;
|
constexpr int16_t POS_X_MONTH = 0;
|
||||||
constexpr int16_t POS_X_YEAR = 72;
|
constexpr int16_t POS_X_YEAR = 72;
|
||||||
constexpr int16_t POS_Y_PLUS = -50;
|
|
||||||
constexpr int16_t POS_Y_TEXT = -6;
|
constexpr int16_t POS_Y_TEXT = -6;
|
||||||
constexpr int16_t POS_Y_MINUS = 40;
|
|
||||||
|
|
||||||
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||||
auto* screen = static_cast<SettingSetDate*>(obj->user_data);
|
auto* screen = static_cast<SettingSetDate*>(obj->user_data);
|
||||||
screen->HandleButtonPress(obj, event);
|
if (event == LV_EVENT_CLICKED) {
|
||||||
|
screen->HandleButtonPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueChangedHandler(void* userData) {
|
||||||
|
auto* screen = static_cast<SettingSetDate*>(userData);
|
||||||
|
screen->CheckDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaximumDayOfMonth(uint8_t month, uint16_t year) {
|
||||||
|
switch (month) {
|
||||||
|
case 2: {
|
||||||
|
if ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)) {
|
||||||
|
return 29;
|
||||||
|
}
|
||||||
|
return 28;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
case 6:
|
||||||
|
case 9:
|
||||||
|
case 11:
|
||||||
|
return 30;
|
||||||
|
default:
|
||||||
|
return 31;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,128 +58,44 @@ SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime
|
||||||
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
||||||
|
|
||||||
dayValue = static_cast<int>(dateTimeController.Day());
|
dayCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
|
||||||
lblDay = lv_label_create(lv_scr_act(), nullptr);
|
dayCounter.Create();
|
||||||
lv_label_set_text_fmt(lblDay, "%d", dayValue);
|
dayCounter.SetValue(dateTimeController.Day());
|
||||||
lv_label_set_align(lblDay, LV_LABEL_ALIGN_CENTER);
|
lv_obj_align(dayCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
|
||||||
lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
|
|
||||||
lv_obj_set_auto_realign(lblDay, true);
|
|
||||||
|
|
||||||
monthValue = static_cast<int>(dateTimeController.Month());
|
monthCounter.EnableMonthMode();
|
||||||
lblMonth = lv_label_create(lv_scr_act(), nullptr);
|
monthCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
|
||||||
UpdateMonthLabel();
|
monthCounter.Create();
|
||||||
lv_label_set_align(lblMonth, LV_LABEL_ALIGN_CENTER);
|
monthCounter.SetValue(static_cast<int>(dateTimeController.Month()));
|
||||||
lv_obj_align(lblMonth, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT);
|
lv_obj_align(monthCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT);
|
||||||
lv_obj_set_auto_realign(lblMonth, true);
|
|
||||||
|
|
||||||
yearValue = static_cast<int>(dateTimeController.Year());
|
yearCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
|
||||||
if (yearValue < 2021)
|
yearCounter.Create();
|
||||||
yearValue = 2021;
|
yearCounter.SetValue(dateTimeController.Year());
|
||||||
lblYear = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_align(yearCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT);
|
||||||
lv_label_set_text_fmt(lblYear, "%d", yearValue);
|
|
||||||
lv_label_set_align(lblYear, LV_LABEL_ALIGN_CENTER);
|
|
||||||
lv_obj_align(lblYear, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT);
|
|
||||||
lv_obj_set_auto_realign(lblYear, true);
|
|
||||||
|
|
||||||
btnDayPlus = lv_btn_create(lv_scr_act(), nullptr);
|
|
||||||
btnDayPlus->user_data = this;
|
|
||||||
lv_obj_set_size(btnDayPlus, 50, 40);
|
|
||||||
lv_obj_align(btnDayPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_PLUS);
|
|
||||||
lv_obj_set_style_local_value_str(btnDayPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
|
|
||||||
lv_obj_set_event_cb(btnDayPlus, event_handler);
|
|
||||||
|
|
||||||
btnDayMinus = lv_btn_create(lv_scr_act(), nullptr);
|
|
||||||
btnDayMinus->user_data = this;
|
|
||||||
lv_obj_set_size(btnDayMinus, 50, 40);
|
|
||||||
lv_obj_align(btnDayMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_MINUS);
|
|
||||||
lv_obj_set_style_local_value_str(btnDayMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
|
|
||||||
lv_obj_set_event_cb(btnDayMinus, event_handler);
|
|
||||||
|
|
||||||
btnMonthPlus = lv_btn_create(lv_scr_act(), nullptr);
|
|
||||||
btnMonthPlus->user_data = this;
|
|
||||||
lv_obj_set_size(btnMonthPlus, 50, 40);
|
|
||||||
lv_obj_align(btnMonthPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_PLUS);
|
|
||||||
lv_obj_set_style_local_value_str(btnMonthPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
|
|
||||||
lv_obj_set_event_cb(btnMonthPlus, event_handler);
|
|
||||||
|
|
||||||
btnMonthMinus = lv_btn_create(lv_scr_act(), nullptr);
|
|
||||||
btnMonthMinus->user_data = this;
|
|
||||||
lv_obj_set_size(btnMonthMinus, 50, 40);
|
|
||||||
lv_obj_align(btnMonthMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_MINUS);
|
|
||||||
lv_obj_set_style_local_value_str(btnMonthMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
|
|
||||||
lv_obj_set_event_cb(btnMonthMinus, event_handler);
|
|
||||||
|
|
||||||
btnYearPlus = lv_btn_create(lv_scr_act(), nullptr);
|
|
||||||
btnYearPlus->user_data = this;
|
|
||||||
lv_obj_set_size(btnYearPlus, 50, 40);
|
|
||||||
lv_obj_align(btnYearPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_PLUS);
|
|
||||||
lv_obj_set_style_local_value_str(btnYearPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
|
|
||||||
lv_obj_set_event_cb(btnYearPlus, event_handler);
|
|
||||||
|
|
||||||
btnYearMinus = lv_btn_create(lv_scr_act(), nullptr);
|
|
||||||
btnYearMinus->user_data = this;
|
|
||||||
lv_obj_set_size(btnYearMinus, 50, 40);
|
|
||||||
lv_obj_align(btnYearMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_MINUS);
|
|
||||||
lv_obj_set_style_local_value_str(btnYearMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
|
|
||||||
lv_obj_set_event_cb(btnYearMinus, event_handler);
|
|
||||||
|
|
||||||
btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
|
btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
|
||||||
btnSetTime->user_data = this;
|
btnSetTime->user_data = this;
|
||||||
lv_obj_set_size(btnSetTime, 120, 48);
|
lv_obj_set_size(btnSetTime, 120, 48);
|
||||||
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||||
|
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_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
|
lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
|
||||||
lv_obj_set_event_cb(btnSetTime, event_handler);
|
lv_obj_set_event_cb(btnSetTime, event_handler);
|
||||||
|
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSetDate::~SettingSetDate() {
|
SettingSetDate::~SettingSetDate() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingSetDate::HandleButtonPress(lv_obj_t* object, lv_event_t event) {
|
void SettingSetDate::HandleButtonPress() {
|
||||||
if (event != LV_EVENT_CLICKED)
|
const uint16_t yearValue = yearCounter.GetValue();
|
||||||
return;
|
const uint8_t monthValue = monthCounter.GetValue();
|
||||||
|
const uint8_t dayValue = dayCounter.GetValue();
|
||||||
if (object == btnDayPlus) {
|
|
||||||
dayValue++;
|
|
||||||
if (dayValue > MaximumDayOfMonth())
|
|
||||||
dayValue = 1;
|
|
||||||
lv_label_set_text_fmt(lblDay, "%d", dayValue);
|
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
|
||||||
} else if (object == btnDayMinus) {
|
|
||||||
dayValue--;
|
|
||||||
if (dayValue < 1)
|
|
||||||
dayValue = MaximumDayOfMonth();
|
|
||||||
lv_label_set_text_fmt(lblDay, "%d", dayValue);
|
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
|
||||||
} else if (object == btnMonthPlus) {
|
|
||||||
monthValue++;
|
|
||||||
if (monthValue > 12)
|
|
||||||
monthValue = 1;
|
|
||||||
UpdateMonthLabel();
|
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
|
||||||
CheckDay();
|
|
||||||
} else if (object == btnMonthMinus) {
|
|
||||||
monthValue--;
|
|
||||||
if (monthValue < 1)
|
|
||||||
monthValue = 12;
|
|
||||||
UpdateMonthLabel();
|
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
|
||||||
CheckDay();
|
|
||||||
} else if (object == btnYearPlus) {
|
|
||||||
yearValue++;
|
|
||||||
lv_label_set_text_fmt(lblYear, "%d", yearValue);
|
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
|
||||||
CheckDay();
|
|
||||||
} else if (object == btnYearMinus) {
|
|
||||||
yearValue--;
|
|
||||||
lv_label_set_text_fmt(lblYear, "%d", yearValue);
|
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
|
||||||
CheckDay();
|
|
||||||
} else if (object == btnSetTime) {
|
|
||||||
NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue);
|
NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue);
|
||||||
dateTimeController.SetTime(static_cast<uint16_t>(yearValue),
|
dateTimeController.SetTime(yearValue,
|
||||||
static_cast<uint8_t>(monthValue),
|
monthValue,
|
||||||
static_cast<uint8_t>(dayValue),
|
dayValue,
|
||||||
0,
|
0,
|
||||||
dateTimeController.Hours(),
|
dateTimeController.Hours(),
|
||||||
dateTimeController.Minutes(),
|
dateTimeController.Minutes(),
|
||||||
|
@ -164,35 +103,9 @@ void SettingSetDate::HandleButtonPress(lv_obj_t* object, lv_event_t event) {
|
||||||
nrf_rtc_counter_get(portNRF_RTC_REG));
|
nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||||
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
|
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int SettingSetDate::MaximumDayOfMonth() const {
|
|
||||||
switch (monthValue) {
|
|
||||||
case 2:
|
|
||||||
if ((((yearValue % 4) == 0) && ((yearValue % 100) != 0)) || ((yearValue % 400) == 0))
|
|
||||||
return 29;
|
|
||||||
return 28;
|
|
||||||
case 4:
|
|
||||||
case 6:
|
|
||||||
case 9:
|
|
||||||
case 11:
|
|
||||||
return 30;
|
|
||||||
default:
|
|
||||||
return 31;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingSetDate::CheckDay() {
|
void SettingSetDate::CheckDay() {
|
||||||
int maxDay = MaximumDayOfMonth();
|
const int maxDay = MaximumDayOfMonth(monthCounter.GetValue(), yearCounter.GetValue());
|
||||||
if (dayValue > maxDay) {
|
dayCounter.SetMax(maxDay);
|
||||||
dayValue = maxDay;
|
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
|
||||||
lv_label_set_text_fmt(lblDay, "%d", dayValue);
|
|
||||||
lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingSetDate::UpdateMonthLabel() {
|
|
||||||
lv_label_set_text_static(
|
|
||||||
lblMonth,
|
|
||||||
Pinetime::Controllers::DateTime::MonthShortToStringLow(static_cast<Pinetime::Controllers::DateTime::Months>(monthValue)));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
#include "components/datetime/DateTimeController.h"
|
#include "components/datetime/DateTimeController.h"
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
|
#include "displayapp/widgets/Counter.h"
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
|
@ -13,28 +14,17 @@ namespace Pinetime {
|
||||||
SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController);
|
SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController);
|
||||||
~SettingSetDate() override;
|
~SettingSetDate() override;
|
||||||
|
|
||||||
void HandleButtonPress(lv_obj_t* object, lv_event_t event);
|
void HandleButtonPress();
|
||||||
|
void CheckDay();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Controllers::DateTime& dateTimeController;
|
Controllers::DateTime& dateTimeController;
|
||||||
|
|
||||||
int dayValue;
|
|
||||||
int monthValue;
|
|
||||||
int yearValue;
|
|
||||||
lv_obj_t* lblDay;
|
|
||||||
lv_obj_t* lblMonth;
|
|
||||||
lv_obj_t* lblYear;
|
|
||||||
lv_obj_t* btnDayPlus;
|
|
||||||
lv_obj_t* btnDayMinus;
|
|
||||||
lv_obj_t* btnMonthPlus;
|
|
||||||
lv_obj_t* btnMonthMinus;
|
|
||||||
lv_obj_t* btnYearPlus;
|
|
||||||
lv_obj_t* btnYearMinus;
|
|
||||||
lv_obj_t* btnSetTime;
|
lv_obj_t* btnSetTime;
|
||||||
|
|
||||||
int MaximumDayOfMonth() const;
|
Widgets::Counter dayCounter = Widgets::Counter(1, 31, jetbrains_mono_bold_20);
|
||||||
void CheckDay();
|
Widgets::Counter monthCounter = Widgets::Counter(1, 12, jetbrains_mono_bold_20);
|
||||||
void UpdateMonthLabel();
|
Widgets::Counter yearCounter = Widgets::Counter(1970, 9999, jetbrains_mono_bold_20);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
#include "components/settings/Settings.h"
|
#include "components/settings/Settings.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -67,8 +68,7 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app,
|
||||||
lv_obj_set_size(btnSetTime, 120, 50);
|
lv_obj_set_size(btnSetTime, 120, 50);
|
||||||
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
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_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_DEFAULT, Colors::bgAlt);
|
||||||
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_value_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_GRAY);
|
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);
|
lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "displayapp/DisplayApp.h"
|
#include "displayapp/DisplayApp.h"
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
|
|
||||||
|
@ -123,8 +124,7 @@ void SettingShakeThreshold::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||||
vCalTime = xTaskGetTickCount();
|
vCalTime = xTaskGetTickCount();
|
||||||
lv_label_set_text_static(calLabel, "Ready!");
|
lv_label_set_text_static(calLabel, "Ready!");
|
||||||
lv_obj_set_click(positionArc, false);
|
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, Colors::highlight);
|
||||||
lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
|
|
||||||
} else if (lv_btn_get_state(calButton) == LV_BTN_STATE_RELEASED) {
|
} else if (lv_btn_get_state(calButton) == LV_BTN_STATE_RELEASED) {
|
||||||
calibrating = 0;
|
calibrating = 0;
|
||||||
lv_obj_set_click(positionArc, true);
|
lv_obj_set_click(positionArc, true);
|
||||||
|
|
|
@ -17,7 +17,6 @@ SettingSteps::SettingSteps(Pinetime::Applications::DisplayApp* app, Pinetime::Co
|
||||||
|
|
||||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
// lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
|
||||||
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
||||||
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
||||||
|
|
|
@ -21,7 +21,6 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pine
|
||||||
|
|
||||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
|
||||||
|
|
||||||
// lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
|
|
||||||
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||||
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
||||||
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "displayapp/widgets/Counter.h"
|
#include "displayapp/widgets/Counter.h"
|
||||||
|
#include "components/datetime/DateTimeController.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Widgets;
|
using namespace Pinetime::Applications::Widgets;
|
||||||
|
|
||||||
|
@ -16,9 +18,17 @@ namespace {
|
||||||
widget->DownBtnPressed();
|
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}, 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() {
|
void Counter::UpBtnPressed() {
|
||||||
|
@ -70,12 +80,14 @@ void Counter::UpdateLabel() {
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
lv_label_set_text_static(number, "12");
|
lv_label_set_text_static(number, "12");
|
||||||
} else if (value <= 12) {
|
} else if (value <= 12) {
|
||||||
lv_label_set_text_fmt(number, "%.2i", value);
|
lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value);
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
lv_label_set_text_fmt(number, "%.2i", value);
|
lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,25 +97,43 @@ void Counter::EnableTwelveHourMode() {
|
||||||
twelveHourMode = true;
|
twelveHourMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value is kept between 1 and 12, but the displayed value is the corresponding month
|
||||||
|
// Make sure to set the max and min values to 1 and 12. Otherwise behaviour is undefined
|
||||||
|
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) {
|
||||||
|
value = max;
|
||||||
|
UpdateLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Counter::SetValueChangedEventCallback(void* userData, void (*handler)(void* userData)) {
|
void Counter::SetValueChangedEventCallback(void* userData, void (*handler)(void* userData)) {
|
||||||
this->userData = userData;
|
this->userData = userData;
|
||||||
this->ValueChangedHandler = handler;
|
this->ValueChangedHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Counter::Create() {
|
void Counter::Create() {
|
||||||
constexpr lv_color_t bgColor = LV_COLOR_MAKE(0x38, 0x38, 0x38);
|
|
||||||
|
|
||||||
counterContainer = lv_obj_create(lv_scr_act(), nullptr);
|
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);
|
number = lv_label_create(counterContainer, nullptr);
|
||||||
lv_obj_set_style_local_text_font(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &font);
|
lv_obj_set_style_local_text_font(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &font);
|
||||||
lv_obj_align(number, nullptr, LV_ALIGN_CENTER, 0, 0);
|
lv_obj_align(number, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
lv_obj_set_auto_realign(number, true);
|
lv_obj_set_auto_realign(number, true);
|
||||||
lv_label_set_text_static(number, "00");
|
if (monthMode) {
|
||||||
|
lv_label_set_text_static(number, "Jan");
|
||||||
|
} else {
|
||||||
|
lv_label_set_text_fmt(number, "%d", max);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr uint8_t padding = 5;
|
static constexpr uint8_t padding = 5;
|
||||||
const uint8_t width = lv_obj_get_width(number) + padding * 2;
|
const uint8_t width = std::max(lv_obj_get_width(number) + padding * 2, 58);
|
||||||
static constexpr uint8_t btnHeight = 50;
|
static constexpr uint8_t btnHeight = 50;
|
||||||
const uint8_t containerHeight = btnHeight * 2 + lv_obj_get_height(number) + padding * 2;
|
const uint8_t containerHeight = btnHeight * 2 + lv_obj_get_height(number) + padding * 2;
|
||||||
|
|
||||||
|
@ -112,7 +142,7 @@ void Counter::Create() {
|
||||||
UpdateLabel();
|
UpdateLabel();
|
||||||
|
|
||||||
upBtn = lv_btn_create(counterContainer, nullptr);
|
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_set_size(upBtn, width, btnHeight);
|
||||||
lv_obj_align(upBtn, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0);
|
lv_obj_align(upBtn, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||||
upBtn->user_data = this;
|
upBtn->user_data = this;
|
||||||
|
@ -124,7 +154,7 @@ void Counter::Create() {
|
||||||
lv_obj_align(upLabel, nullptr, LV_ALIGN_CENTER, 0, 0);
|
lv_obj_align(upLabel, nullptr, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
downBtn = lv_btn_create(counterContainer, nullptr);
|
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_set_size(downBtn, width, btnHeight);
|
||||||
lv_obj_align(downBtn, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
lv_obj_align(downBtn, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||||
downBtn->user_data = this;
|
downBtn->user_data = this;
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace Pinetime {
|
||||||
void HideControls();
|
void HideControls();
|
||||||
void ShowControls();
|
void ShowControls();
|
||||||
void EnableTwelveHourMode();
|
void EnableTwelveHourMode();
|
||||||
|
void EnableMonthMode();
|
||||||
|
void SetMax(int newMax);
|
||||||
void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData));
|
void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData));
|
||||||
|
|
||||||
int GetValue() const {
|
int GetValue() const {
|
||||||
|
@ -36,10 +38,12 @@ namespace Pinetime {
|
||||||
lv_obj_t* upperLine;
|
lv_obj_t* upperLine;
|
||||||
lv_obj_t* lowerLine;
|
lv_obj_t* lowerLine;
|
||||||
lv_point_t linePoints[2];
|
lv_point_t linePoints[2];
|
||||||
int value = 0;
|
|
||||||
int min;
|
int min;
|
||||||
int max;
|
int max;
|
||||||
|
int value;
|
||||||
|
const int leadingZeroCount;
|
||||||
bool twelveHourMode = false;
|
bool twelveHourMode = false;
|
||||||
|
bool monthMode = false;
|
||||||
lv_font_t& font;
|
lv_font_t& font;
|
||||||
|
|
||||||
void* userData = nullptr;
|
void* userData = nullptr;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "displayapp/widgets/PageIndicator.h"
|
#include "displayapp/widgets/PageIndicator.h"
|
||||||
|
#include "displayapp/InfiniTimeTheme.h"
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Widgets;
|
using namespace Pinetime::Applications::Widgets;
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ void PageIndicator::Create() {
|
||||||
|
|
||||||
pageIndicatorBase = lv_line_create(lv_scr_act(), nullptr);
|
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_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);
|
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
|
||||||
|
|
||||||
const int16_t indicatorSize = LV_VER_RES / nScreens;
|
const int16_t indicatorSize = LV_VER_RES / nScreens;
|
||||||
|
@ -26,6 +27,6 @@ void PageIndicator::Create() {
|
||||||
|
|
||||||
pageIndicator = lv_line_create(lv_scr_act(), nullptr);
|
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_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);
|
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ void StatusIcons::Create() {
|
||||||
lv_label_set_text_static(bleIcon, Screens::Symbols::bluetooth);
|
lv_label_set_text_static(bleIcon, Screens::Symbols::bluetooth);
|
||||||
|
|
||||||
batteryPlug = lv_label_create(container, nullptr);
|
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);
|
lv_label_set_text_static(batteryPlug, Screens::Symbols::plug);
|
||||||
|
|
||||||
batteryIcon.Create(container);
|
batteryIcon.Create(container);
|
||||||
|
|
|
@ -21,7 +21,10 @@ void St7789::Init() {
|
||||||
MemoryDataAccessControl();
|
MemoryDataAccessControl();
|
||||||
ColumnAddressSet();
|
ColumnAddressSet();
|
||||||
RowAddressSet();
|
RowAddressSet();
|
||||||
|
// P8B Mirrored version does not need display inversion.
|
||||||
|
#ifndef DRIVER_DISPLAY_MIRROR
|
||||||
DisplayInversionOn();
|
DisplayInversionOn();
|
||||||
|
#endif
|
||||||
NormalModeOn();
|
NormalModeOn();
|
||||||
SetVdv();
|
SetVdv();
|
||||||
DisplayOn();
|
DisplayOn();
|
||||||
|
@ -62,7 +65,18 @@ void St7789::ColMod() {
|
||||||
|
|
||||||
void St7789::MemoryDataAccessControl() {
|
void St7789::MemoryDataAccessControl() {
|
||||||
WriteCommand(static_cast<uint8_t>(Commands::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);
|
WriteData(0x00);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void St7789::ColumnAddressSet() {
|
void St7789::ColumnAddressSet() {
|
||||||
|
|
|
@ -161,7 +161,7 @@ typedef void* lv_anim_user_data_t;
|
||||||
#define LV_USE_OUTLINE 0
|
#define LV_USE_OUTLINE 0
|
||||||
|
|
||||||
/*1: enable pattern drawing on rectangles*/
|
/*1: enable pattern drawing on rectangles*/
|
||||||
#define LV_USE_PATTERN 0
|
#define LV_USE_PATTERN 1
|
||||||
|
|
||||||
/*1: enable value string drawing on rectangles*/
|
/*1: enable value string drawing on rectangles*/
|
||||||
#define LV_USE_VALUE_STR 1
|
#define LV_USE_VALUE_STR 1
|
||||||
|
|
|
@ -251,7 +251,8 @@ void SystemTask::Work() {
|
||||||
case Messages::TouchWakeUp: {
|
case Messages::TouchWakeUp: {
|
||||||
if (touchHandler.GetNewTouchInfo()) {
|
if (touchHandler.GetNewTouchInfo()) {
|
||||||
auto gesture = touchHandler.GestureGet();
|
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 &&
|
((gesture == Pinetime::Applications::TouchEvents::DoubleTap &&
|
||||||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) ||
|
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) ||
|
||||||
(gesture == Pinetime::Applications::TouchEvents::Tap &&
|
(gesture == Pinetime::Applications::TouchEvents::Tap &&
|
||||||
|
@ -280,7 +281,7 @@ void SystemTask::Work() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Messages::OnNewNotification:
|
case Messages::OnNewNotification:
|
||||||
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) {
|
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) {
|
||||||
if (state == SystemTaskState::Sleeping) {
|
if (state == SystemTaskState::Sleeping) {
|
||||||
GoToRunning();
|
GoToRunning();
|
||||||
} else {
|
} else {
|
||||||
|
@ -388,7 +389,8 @@ void SystemTask::Work() {
|
||||||
break;
|
break;
|
||||||
case Messages::OnNewHour:
|
case Messages::OnNewHour:
|
||||||
using Pinetime::Controllers::AlarmController;
|
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) {
|
alarmController.State() != AlarmController::AlarmState::Alerting) {
|
||||||
if (state == SystemTaskState::Sleeping) {
|
if (state == SystemTaskState::Sleeping) {
|
||||||
GoToRunning();
|
GoToRunning();
|
||||||
|
@ -399,7 +401,8 @@ void SystemTask::Work() {
|
||||||
break;
|
break;
|
||||||
case Messages::OnNewHalfHour:
|
case Messages::OnNewHalfHour:
|
||||||
using Pinetime::Controllers::AlarmController;
|
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) {
|
alarmController.State() != AlarmController::AlarmState::Alerting) {
|
||||||
if (state == SystemTaskState::Sleeping) {
|
if (state == SystemTaskState::Sleeping) {
|
||||||
GoToRunning();
|
GoToRunning();
|
||||||
|
@ -483,13 +486,13 @@ void SystemTask::UpdateMotion() {
|
||||||
motionController.IsSensorOk(motionSensor.IsOk());
|
motionController.IsSensorOk(motionSensor.IsOk());
|
||||||
motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps);
|
motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps);
|
||||||
|
|
||||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) &&
|
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) {
|
||||||
motionController.Should_RaiseWake(state == SystemTaskState::Sleeping)) {
|
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();
|
GoToRunning();
|
||||||
}
|
}
|
||||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) &&
|
|
||||||
motionController.Should_ShakeWake(settingsController.GetShakeThreshold())) {
|
|
||||||
GoToRunning();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|