Merge branch 'develop' of JF/PineTime into master
@ -21,8 +21,8 @@ AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
@ -52,14 +52,14 @@ BreakStringLiterals: true
|
||||
ColumnLimit: 140
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ExperimentalAutoDetectBinPacking: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
@ -90,10 +90,6 @@ MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
|
@ -22,5 +22,9 @@ Checks: '*,
|
||||
-hicpp-no-assembler,
|
||||
-hicpp-avoid-c-arrays,
|
||||
-hicpp-uppercase-literal-suffix,
|
||||
-hicpp-no-array-decay,
|
||||
-cert-err58-cpp,
|
||||
-cert-err60-cpp'
|
||||
-cert-err60-cpp'
|
||||
CheckOptions:
|
||||
- key: readability-function-cognitive-complexity.Threshold
|
||||
value: 100
|
3
.gitignore
vendored
@ -1,4 +1,7 @@
|
||||
.idea/
|
||||
# Python virtual environment for DFU images
|
||||
.venv/
|
||||
|
||||
# CMake
|
||||
cmake-build-*
|
||||
cmake-*
|
||||
|
@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(pinetime VERSION 1.0.0 LANGUAGES C CXX ASM)
|
||||
project(pinetime VERSION 1.1.0 LANGUAGES C CXX ASM)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
@ -55,10 +55,22 @@ if(BUILD_DFU)
|
||||
set(BUILD_DFU true)
|
||||
endif()
|
||||
|
||||
set(PROJECT_GIT_COMMIT_HASH "")
|
||||
|
||||
execute_process(COMMAND git rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE PROJECT_GIT_COMMIT_HASH
|
||||
RESULT_VARIABLE PROJECT_GIT_COMMIT_HASH_SUCCESS)
|
||||
|
||||
string(STRIP ${PROJECT_GIT_COMMIT_HASH} PROJECT_GIT_COMMIT_HASH)
|
||||
|
||||
message("PROJECT_GIT_COMMIT_HASH_SUCCESS? " ${PROJECT_GIT_COMMIT_HASH_SUCCESS})
|
||||
|
||||
message("BUILD CONFIGURATION")
|
||||
message("-------------------")
|
||||
message(" * Version : " ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
message(" * Toolchain : " ${ARM_NONE_EABI_TOOLCHAIN_PATH})
|
||||
message(" * GitRef(S) : " ${PROJECT_GIT_COMMIT_HASH})
|
||||
message(" * NRF52 SDK : " ${NRF5_SDK_PATH})
|
||||
set(PROGRAMMER "???")
|
||||
if(USE_JLINK)
|
||||
|
34
README.md
@ -24,8 +24,7 @@ The goal of this project is to design an open-source firmware for the Pinetime s
|
||||
|
||||
## Overview
|
||||
|
||||
![Pinetime screens](images/0.14.0/collage1.png "PinetimeScreens")
|
||||
![Pinetime screens](images/0.14.0/collage2.png "PinetimeScreens")
|
||||
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
|
||||
|
||||
As of now, here is the list of achievements of this project:
|
||||
|
||||
@ -37,10 +36,15 @@ As of now, here is the list of achievements of this project:
|
||||
- Heart rate measurements
|
||||
- Step counting
|
||||
- Wake-up on wrist rotation
|
||||
- Multiple 'apps' :
|
||||
* Clock (displays the date, time, battery level, ble connection status, heart rate)
|
||||
* System info (displays various info : BLE MAC, build date/time, uptime, version,...)
|
||||
* Brightess (allows the user to configure the brightness of the display)
|
||||
- Quick actions
|
||||
* Disable vibration on notification
|
||||
* Brightness settings
|
||||
* Flashlight
|
||||
* Settings
|
||||
- 2 watch faces:
|
||||
* Digital
|
||||
* Analog
|
||||
- Multiple 'apps' :
|
||||
* Music (control the playback of the music on your phone)
|
||||
* Heart rate (controls the heart rate sensor and display current heartbeat)
|
||||
* Navigation (displays navigation instructions coming from the companion app)
|
||||
@ -48,21 +52,31 @@ As of now, here is the list of achievements of this project:
|
||||
* Paddle (single player pong-like game)
|
||||
* Two (2048 clone game)
|
||||
* Stopwatch (with all the necessary functions such as play, pause, lap, stop)
|
||||
* Motion sensor and step counter (displays the number of steps and the state of the motion sensor in real-time)
|
||||
- User settings:
|
||||
* Display timeout
|
||||
* Wake-up condition
|
||||
* Time format (12/24h)
|
||||
* Default watch face
|
||||
* Battery status
|
||||
* Firmware validation
|
||||
* System information
|
||||
- Supported by 3 companion apps (development is in progress):
|
||||
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android)
|
||||
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
||||
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
|
||||
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
|
||||
- **[Experimental]** OTA (Over-the-air) update via BLE
|
||||
- **[Experimental]** Bootloader based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
||||
- OTA (Over-the-air) update via BLE
|
||||
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
||||
|
||||
## Documentation
|
||||
|
||||
### Getting started
|
||||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/gettingStarted.md)
|
||||
- [Getting started with InfiniTime 1.0 (quick user guide, update bootloader and InfiniTime,...)](doc/gettingStarted/gettingStarted-1.0.md)
|
||||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/ota-gadgetbridge-nrfconnect.md)
|
||||
|
||||
### Develop
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/Readme.md)
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
||||
|
||||
### Build, flash and debug
|
||||
|
@ -3,6 +3,7 @@
|
||||
To build this project, you'll need:
|
||||
- A cross-compiler : [ARM-GCC (9-2020-q2-update)](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update)
|
||||
- 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 `cbor` and `intelhex` modules for Python 3
|
||||
- A reasonably recent version of CMake (I use 3.16.5)
|
||||
|
||||
## Build steps
|
||||
|
@ -2,37 +2,68 @@
|
||||
## Report bugs
|
||||
You use your Pinetime and find a bug in the firmware? [Create an issue on Github](https://github.com/JF002/InfiniTime/issues) explaining the bug, how to reproduce it, the version of the firmware you use...
|
||||
## Write and improve documentation
|
||||
Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, photo, video,...
|
||||
Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, photo, video,...
|
||||
|
||||
As the documentation is part of the source code, you can submit your improvements to the documentation by submitting a pull request (see below).
|
||||
## 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*.
|
||||
## Spread the word
|
||||
Pinetime is a cool open source project that deserves to be know. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open-source firmware for a smartwatch!
|
||||
The Pinetime is a cool open source project that deserves to be known. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open-source firmware for a smartwatch!
|
||||
|
||||
# How to submit a pull request ?
|
||||
Your contribution is more than welcome!
|
||||
|
||||
If you want to fix a bug, add a functionality or improve the code, you'll first need to create a branch from the **develop** branch (see [this page about the branching model](./branches.md)). This branch is called a feature branch, and you should choose a name that explains what you are working on (ex: "add-doc-about-contributions"). In this branch, try to focus on only one topic, bug or feature. For example, if you created this branch to work on the UI of a specific application, do not commit modifications about the SPI driver. If you want to work on multiple topics, create one branch per topic.
|
||||
## TL;DR
|
||||
- Create a branch from develop;
|
||||
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...);
|
||||
- Test your modifications on the actual hardware;
|
||||
- Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy);
|
||||
- Clean your code and remove files that are not needed;
|
||||
- Write documentation related to your new feature is applicable;
|
||||
- Create the pull-request and write a great description about it : what does your PR do, why, how,... Add pictures and video if possible;
|
||||
- Wait for someone to review your PR and take part in the review process;
|
||||
- Your PR will eventually be merged :)
|
||||
|
||||
When your feature branch is ready, make sure it actually works and do not forget to write documentation about it if necessary.
|
||||
Your contribution is more than welcome!
|
||||
|
||||
Then, you can submit a pull-request for review. Try to describe your pull request as much as possible: what did you do in this branch, how does it work, how is it designed, are there any limitations,... This will help the contributors to understand and review your code easily.
|
||||
If you want to fix a bug, add a functionality or improve the code, you'll first need to create a branch from the **develop** branch (see [this page about the branching model](./branches.md)). This branch is called a feature branch, and you should choose a name that explains what you are working on (ex: "add-doc-about-contributions"). In this branch, **focus on only one topic, bug or feature**. For example, if you created this branch to work on the UI of a specific application, do not commit modifications about the SPI driver. If you want to work on multiple topics, create one branch per topic.
|
||||
|
||||
Other contributors can post comments about the pull request, maybe ask for more info or adjustements in the code.
|
||||
When your feature branch is ready, **make sure it actually works** and **do not forget to write documentation** about it if it's relevant.
|
||||
|
||||
Once the pull request is reviewed an accepted, it'll be merge in **develop** and will be released in the next release version of the firmware.
|
||||
I **strongly discourage to create a PR containing modifications that haven't been tested**. If, for any reason, you cannot test your modifications but want to publish them anyway, **please mention it in the description**. This way, other contributors might be willing to test it and provide feedback about your code.
|
||||
|
||||
Also, before submitting your PR, check the coding style of your code against the **coding conventions** detailed below. This project also provides [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy) configuration files. You can use them to ensure correct formatting of your code.
|
||||
|
||||
Do not forget to check the files you are going to commit and remove those who are not necessary (config files from your IDE, for example). Remove old comments, commented code,...
|
||||
|
||||
Then, you can submit a pull-request for review. Try to **describe your pull request as much as possible**: what did you do in this branch, how does it work, how is it designed, are there any limitations,... This will help the contributors to understand and review your code easily. You can add pictures and video to the description so that contributors will have a quick overview of your work.
|
||||
|
||||
Other contributors can post comments about the pull request, maybe ask for more info or adjustments in the code.
|
||||
|
||||
Once the pull request is reviewed and accepted, it'll be merge in **develop** and will be released in the next release version of the firmware.
|
||||
|
||||
## Why all these rules?
|
||||
Reviewing pull-requests is a **very time consuming task** for the creator of this project ([JF002](https://github.com/JF002)) and for other contributors who take the time to review them. Every little thing you do to make their lives easier will **increase the chances your PR will be merge quickly**.
|
||||
|
||||
When reviewing PR, the author and contributors will first look at the **description**. If it's easy to understand what the PR does, why the modification is needed or interesting and how it's done, a good part of the work is already done : we understand the PR and its context.
|
||||
|
||||
Then, reviewing **a few files that were modified for a single purpose** is a lot more easier than to review 30 files modified for many reasons (bug fix, UI improvements, typos in doc,...), even if all these changes make sense. Also, it's possible that we agree on some modification but not on some other, and we won't be able to merge the PR because of the changes that are not accepted.
|
||||
|
||||
We do our best to keep the code as consistent as possible, and that mean we pay attention to the **formatting** of the code. If the code formatting is not consistent with our code base, we'll ask you to review it, which will take more time.
|
||||
|
||||
The last step of the review consists in **testing** the modification. If it doesn't work out of the box, we'll ask your to review your code and to ensure that it works as expected.
|
||||
|
||||
It's totally normal for a PR to need some more work even after it was created, that's why we review them. But every round trip takes time, and it's good practice to try to reduce them as much as possible by following those simple rules.
|
||||
|
||||
# Coding convention
|
||||
## Language
|
||||
The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction.
|
||||
|
||||
It's OK to include C code if this code comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
||||
It's OK to include C code if this code comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
||||
|
||||
## Coding style
|
||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
||||
|
||||
- **Identation** : 2 spaces, no tabulation
|
||||
- **Indentation** : 2 spaces, no tabulation
|
||||
- **Opening brace** at the end of the line
|
||||
- **Naming** : Choose self-describing variable name
|
||||
- **class** : PascalCase
|
||||
|
BIN
doc/gettingStarted/appmenu-071.jpg
Normal file
After Width: | Height: | Size: 107 KiB |
BIN
doc/gettingStarted/appmenu.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
doc/gettingStarted/bootloader-1.0.jpg
Normal file
After Width: | Height: | Size: 156 KiB |
112
doc/gettingStarted/gettingStarted-1.0.md
Normal file
@ -0,0 +1,112 @@
|
||||
# Getting started with InfiniTime 1.0
|
||||
On April 22 2021, InfiniTime and Pine64 [announced the release of InfiniTime 1.0](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as *enthusiast grade end-user product*. This page aims to guide you with your first step with your new PineTime.
|
||||
|
||||
## Firmware, InfiniTime, Bootloader, Recovery firmware, OTA, DFU... What is it?
|
||||
You might have already seen these words by reading the announcement, release notes, or [the wiki guide](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0) and, you may find them misleading if you're not familiar with the project.
|
||||
|
||||
Basically, a **firmware** is just a software running on the embedded hardware of a device, the PineTime in this case.
|
||||
**InfiniTime** is based on 3 distinct **firmwares**:
|
||||
- **[InfiniTime](https://github.com/JF002/InfiniTime)** itself, this is the *application firmware* running on the PineTime. This is the main firmware which provides most of the functionalities you'll use on a daily basis : bluetooth low-energy (BLE) connectivity, applications, watchfaces,...
|
||||
- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying **updates** of the *application firmware*, reverting them in case of issues and load the recovery firmware when requested.
|
||||
- **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/JF002/InfiniTime/releases/tag/0.14.1).
|
||||
|
||||
**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**igital **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).
|
||||
|
||||
## How to check the version of InfiniTime and the bootloader?
|
||||
Since September 2020, all PineTimes (devkits or sealed) are flashed using the **[first iteration of the bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7)** and **[InfiniTime 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1)**. There was no recovery firmware at that time.
|
||||
|
||||
The bootloader only runs when the watch starts (from an empty battery, for example) or after a reset (after a succesful OTA or a manual reset - long push on the button).
|
||||
|
||||
You can recognize this first iteration of the bootloader with it greenish **PINETIME** logo.
|
||||
|
||||
![Old bootloader logo](oldbootloaderlogo.jpg)
|
||||
|
||||
You can check the version of InfiniTime by opening the app *SystemInfo*. For version < 1.0:
|
||||
|
||||
![InfiniTime 0.7.1 Application menu](appmenu-071.jpg)
|
||||
![InfiniTime 0.7.1 version](version-071.jpg)
|
||||
|
||||
And for version >= 1.0 :
|
||||
|
||||
![InfiniTime 1.0 version](version-1.0.jpg)
|
||||
|
||||
|
||||
PineTime shipped from June 2020 (to be confirmed) will be flashed with the [new version of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0), the [recovery firmware](https://github.com/JF002/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/tag/1.0.0).
|
||||
|
||||
The bootloader is easily recognizable with it white pine cone that is progressively drawn in green. It also displays its own version on the bottom (1.0.0 as of now).
|
||||
|
||||
![Bootloader 1.0](bootloader-1.0.jpg)
|
||||
|
||||
## How to update your PineTime?
|
||||
To update your PineTime, you can use one of the compatible companion applications. Here are the main ones:
|
||||
|
||||
- **[Amazfish](https://github.com/piggz/harbour-amazfish)** (Desktop Linux, mobile Linux, SailfishOS, runs on the PinebookPro and the Pinephone)
|
||||
- **[Gadgetbridge](https://www.gadgetbridge.org/)** (Android)
|
||||
- **[Siglo](https://github.com/alexr4535/siglo)** (Linux, GTK based)
|
||||
- **NRFConnect** (closed source, Android & iOS).
|
||||
|
||||
See [this page](ota-gadgetbridge-nrfconnect.md) for more info about the OTA procedure using Gadgetbrige and NRFCOnnect.
|
||||
|
||||
### From InfiniTime 0.7.1 / old bootloader
|
||||
If your PineTime is currently running InfiniTime 0.7.1 and the old bootloader, we strongly recommend you update them to more recent version (Bootloader 1.0.0 and InfiniTime 1.0.0 as of now). We also recommend you install the recovery firmware once the bootloader is up-do-date.
|
||||
|
||||
Using the companion app of your choice, you'll need to apply the OTA procedure for these 3 firmwares in this sequence (failing to follow this specific order might temporarily or permanently brick your device):
|
||||
|
||||
1. Flash the latest version of InfiniTime. The file to upload is named **pinetime-mcuboot-app-dfu-x.y.z.zip**. Here is the link to [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip).
|
||||
2. Update the bootloader by applying the OTA procedure with the file named [**reloader-mcuboot.zip** from the repo of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/download/1.0.0/reloader-mcuboot.zip).
|
||||
3. Install the recovery firmware by applying the OTA procedure with the file named [**pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip** from the version 0.14.1 of InfiniTime](https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip).
|
||||
|
||||
You'll find more info about this process in [this wiki page](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0). You can also see the procedure in video [here](https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529) and [here (from Amazfish)](https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e)
|
||||
|
||||
### From version > 1.0
|
||||
If you are already running the new "1.0.0" bootloader, all you have to do is update your version of InfiniTime when it'll be available. We'll write specific instructions when (if) we release a new version of the bootloader.
|
||||
|
||||
### Firmware validation
|
||||
The bootloader requires a (manual) validation of the firmware. If the watch reset with an updated firmware that was not validated, the bootloader will consider it as non-functionning and will revert to the previous version of the firmware. This is a safety feature to prevent bricking your device with a faulty firmware.
|
||||
|
||||
You can validate your updated firmware on InfiniTime >= 1.0 by following this simple procedure:
|
||||
|
||||
- From the watchface, swipe **right** to display the *Quick Actions menu*
|
||||
- Open the **Settings** app by tapping the *gear* icon on the bottom right
|
||||
- Swipe down and tap on the entry named **Firmware**
|
||||
- This app shows the version that is currently running. If it's not validated yet, it displays 2 buttons:
|
||||
- **Validate** to validate your firmware
|
||||
- **Reset** to reset the watch and revert to the previously running version of the firmware
|
||||
|
||||
## InfiniTime 1.0 quick user guide
|
||||
### Setting the time
|
||||
By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00). The time will be automatically synchronized once you connect on of the companion app to your PineTime using BLE connectivity. InfiniTime does not provide any way to manually set the time for now.
|
||||
|
||||
### Navigation in the menu
|
||||
|
||||
![Quick actions](quickactions.jpg)
|
||||
![Settings](settings.jpg)
|
||||
![Application menu](appmenu.jpg)
|
||||
|
||||
- Swipe **down** to display the notification panel. Notification sent by your companion app will be displayed in this panel.
|
||||
- Swipe **up** to display the application menus. Apps (stopwatch, music, step, games,...) can be started from this menu.
|
||||
- Swipe **right** to display the Quick Actions menu. This menu allows you to
|
||||
- Set the brightness of the display
|
||||
- Start the **flashlight** app
|
||||
- Enable/disable vibrations on notifications (Do Not Disturb mode)
|
||||
- Enter the **settings** menu
|
||||
- Settings
|
||||
- Display timeout
|
||||
- Wake up event (Tap, wrist rotation)
|
||||
- Time format (12/24H)
|
||||
- Default watchface (digital / analog)
|
||||
- Battery info
|
||||
- Firmware validation
|
||||
- About (system info, firmware version,...)
|
||||
|
||||
### Bootloader
|
||||
|
||||
Most of the time, the bootloader just runs without your intervention (update and load the firmware).
|
||||
|
||||
However, you can enable 2 functionalities using the push button:
|
||||
|
||||
- Push the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the updated one
|
||||
- Push the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
|
||||
|
||||
More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md).
|
||||
|
BIN
doc/gettingStarted/oldbootloaderlogo.jpg
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
doc/gettingStarted/quickactions.jpg
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
doc/gettingStarted/settings.jpg
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
doc/gettingStarted/version-071.jpg
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
doc/gettingStarted/version-1.0.jpg
Normal file
After Width: | Height: | Size: 114 KiB |
3
docker/.gitpod.Dockerfile
vendored
@ -19,8 +19,11 @@ RUN apt-get update -qq \
|
||||
libffi-dev \
|
||||
libssl-dev \
|
||||
python3-dev \
|
||||
git \
|
||||
&& rm -rf /var/cache/apt/* /var/lib/apt/lists/*;
|
||||
|
||||
# Git needed for PROJECT_GIT_COMMIT_HASH variable setting
|
||||
|
||||
# Needs to be installed as root
|
||||
RUN pip3 install adafruit-nrfutil
|
||||
RUN pip3 install -Iv cryptography==3.3
|
||||
|
@ -19,8 +19,11 @@ RUN apt-get update -qq \
|
||||
libssl-dev \
|
||||
python3-dev \
|
||||
python \
|
||||
git \
|
||||
&& rm -rf /var/cache/apt/* /var/lib/apt/lists/*;
|
||||
|
||||
# Git needed for PROJECT_GIT_COMMIT_HASH variable setting
|
||||
|
||||
RUN pip3 install adafruit-nrfutil
|
||||
RUN pip3 install -Iv cryptography==3.3
|
||||
|
||||
|
BIN
images/1.0.0/collage.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
@ -17,7 +17,7 @@ uint32_t BootloaderVersion::Patch() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *BootloaderVersion::VersionString() {
|
||||
const char* BootloaderVersion::VersionString() {
|
||||
return "0.0.0";
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
namespace Pinetime {
|
||||
class BootloaderVersion {
|
||||
public:
|
||||
static uint32_t Major();
|
||||
static uint32_t Minor();
|
||||
static uint32_t Patch();
|
||||
static const char* VersionString();
|
||||
static bool IsValid();
|
||||
public:
|
||||
static uint32_t Major();
|
||||
static uint32_t Minor();
|
||||
static uint32_t Patch();
|
||||
static const char* VersionString();
|
||||
static bool IsValid();
|
||||
};
|
||||
}
|
@ -406,6 +406,8 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/screens/FlashLight.cpp
|
||||
displayapp/screens/List.cpp
|
||||
displayapp/screens/BatteryInfo.cpp
|
||||
displayapp/screens/Steps.cpp
|
||||
displayapp/screens/Timer.cpp
|
||||
|
||||
## Settings
|
||||
displayapp/screens/settings/QuickSettings.cpp
|
||||
@ -414,6 +416,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/screens/settings/SettingTimeFormat.cpp
|
||||
displayapp/screens/settings/SettingWakeUp.cpp
|
||||
displayapp/screens/settings/SettingDisplay.cpp
|
||||
displayapp/screens/settings/SettingSteps.cpp
|
||||
|
||||
## Watch faces
|
||||
displayapp/icons/bg_clock.c
|
||||
@ -457,6 +460,7 @@ list(APPEND SOURCE_FILES
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/motor/MotorController.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
@ -466,6 +470,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/fonts/jetbrains_mono_extrabold_compressed.c
|
||||
displayapp/fonts/jetbrains_mono_bold_20.c
|
||||
displayapp/fonts/jetbrains_mono_76.c
|
||||
displayapp/fonts/jetbrains_mono_42.c
|
||||
displayapp/fonts/lv_font_sys_48.c
|
||||
displayapp/lv_pinetime_theme.c
|
||||
|
||||
@ -517,6 +522,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
||||
components/ble/HeartRateService.cpp
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
@ -587,6 +593,7 @@ set(INCLUDE_FILES
|
||||
displayapp/screens/Notifications.h
|
||||
displayapp/screens/HeartRate.h
|
||||
displayapp/screens/Motion.h
|
||||
displayapp/screens/Timer.h
|
||||
drivers/St7789.h
|
||||
drivers/SpiNorFlash.h
|
||||
drivers/SpiMaster.h
|
||||
@ -616,6 +623,7 @@ set(INCLUDE_FILES
|
||||
components/ble/BleClient.h
|
||||
components/ble/HeartRateService.h
|
||||
components/settings/Settings.h
|
||||
components/timer/TimerController.h
|
||||
drivers/Cst816s.h
|
||||
FreeRTOS/portmacro.h
|
||||
FreeRTOS/portmacro_cmsis.h
|
||||
|
@ -26,20 +26,19 @@
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
#include "nrf_soc.h"
|
||||
#include "nrf_soc.h"
|
||||
#endif
|
||||
#include "app_util_platform.h"
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Possible configurations for system timer
|
||||
*/
|
||||
#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */
|
||||
#define FREERTOS_USE_SYSTICK 1 /**< Use SysTick timer for system */
|
||||
#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */
|
||||
#define FREERTOS_USE_SYSTICK 1 /**< Use SysTick timer for system */
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
@ -55,153 +54,150 @@
|
||||
|
||||
#define configTICK_SOURCE FREERTOS_USE_RTC
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
#define configUSE_TICKLESS_IDLE 1
|
||||
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
|
||||
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||
#define configTICK_RATE_HZ 1024
|
||||
#define configMAX_PRIORITIES ( 3 )
|
||||
#define configMINIMAL_STACK_SIZE ( 120 )
|
||||
#define configTOTAL_HEAP_SIZE ( 1024*16 )
|
||||
#define configMAX_TASK_NAME_LEN ( 4 )
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
|
||||
#define configQUEUE_REGISTRY_SIZE 2
|
||||
#define configUSE_QUEUE_SETS 0
|
||||
#define configUSE_TIME_SLICING 0
|
||||
#define configUSE_NEWLIB_REENTRANT 0
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||
#define configUSE_TICKLESS_IDLE 1
|
||||
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */
|
||||
#define configCPU_CLOCK_HZ (SystemCoreClock)
|
||||
#define configTICK_RATE_HZ 1024
|
||||
#define configMAX_PRIORITIES (3)
|
||||
#define configMINIMAL_STACK_SIZE (120)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 16)
|
||||
#define configMAX_TASK_NAME_LEN (4)
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
|
||||
#define configQUEUE_REGISTRY_SIZE 2
|
||||
#define configUSE_QUEUE_SETS 0
|
||||
#define configUSE_TIME_SLICING 0
|
||||
#define configUSE_NEWLIB_REENTRANT 0
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||
|
||||
/* Hook function related definitions. */
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
|
||||
/* Run time and task stats gathering related definitions. */
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_TRACE_FACILITY 1
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_TRACE_FACILITY 1
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
|
||||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES (2)
|
||||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( 0 )
|
||||
#define configTIMER_QUEUE_LENGTH 32
|
||||
#define configTIMER_TASK_STACK_DEPTH ( 300 )
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY (0)
|
||||
#define configTIMER_QUEUE_LENGTH 32
|
||||
#define configTIMER_TASK_STACK_DEPTH (300)
|
||||
|
||||
/* Tickless Idle configuration. */
|
||||
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
|
||||
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
|
||||
|
||||
/* Tickless idle/low power functionality. */
|
||||
|
||||
|
||||
/* Define to trap errors during development. */
|
||||
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
|
||||
#define configASSERT( x ) ASSERT(x)
|
||||
#define configASSERT(x) ASSERT(x)
|
||||
#endif
|
||||
|
||||
/* FreeRTOS MPU specific definitions. */
|
||||
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1
|
||||
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1
|
||||
|
||||
/* Optional functions - most linkers will remove unused functions anyway. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_xResumeFromISR 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
|
||||
#define INCLUDE_pcTaskGetTaskName 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xEventGroupSetBitFromISR 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 1
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_xResumeFromISR 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
#define INCLUDE_xTaskGetIdleTaskHandle 1
|
||||
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
|
||||
#define INCLUDE_pcTaskGetTaskName 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xEventGroupSetBitFromISR 1
|
||||
#define INCLUDE_xTimerPendFunctionCall 1
|
||||
|
||||
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
||||
function. */
|
||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
|
||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
|
||||
|
||||
/* The highest interrupt priority that can be used by any interrupt service
|
||||
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
||||
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH
|
||||
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH
|
||||
|
||||
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||
#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY
|
||||
#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY
|
||||
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
||||
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
|
||||
|
||||
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||
standard names - or at least those used in the unmodified vector table. */
|
||||
|
||||
#define vPortSVCHandler SVC_Handler
|
||||
#define xPortPendSVHandler PendSV_Handler
|
||||
|
||||
#define vPortSVCHandler SVC_Handler
|
||||
#define xPortPendSVHandler PendSV_Handler
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Settings that are generated automatically
|
||||
* basing on the settings above
|
||||
*/
|
||||
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
||||
// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically
|
||||
// to CPU clock source
|
||||
#define xPortSysTickHandler SysTick_Handler
|
||||
// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically
|
||||
// to CPU clock source
|
||||
#define xPortSysTickHandler SysTick_Handler
|
||||
#elif (configTICK_SOURCE == FREERTOS_USE_RTC)
|
||||
#define configSYSTICK_CLOCK_HZ ( 32768UL )
|
||||
#define xPortSysTickHandler RTC1_IRQHandler
|
||||
#define configSYSTICK_CLOCK_HZ (32768UL)
|
||||
#define xPortSysTickHandler RTC1_IRQHandler
|
||||
#else
|
||||
#error Unsupported configTICK_SOURCE value
|
||||
#error Unsupported configTICK_SOURCE value
|
||||
#endif
|
||||
|
||||
/* Code below should be only used by the compiler, and not the assembler. */
|
||||
#if !(defined(__ASSEMBLY__) || defined(__ASSEMBLER__))
|
||||
#include "nrf.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */
|
||||
/* Cortex-M specific definitions. */
|
||||
#ifdef __NVIC_PRIO_BITS
|
||||
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||
#else
|
||||
#error "This port requires __NVIC_PRIO_BITS to be defined"
|
||||
#endif
|
||||
/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */
|
||||
/* Cortex-M specific definitions. */
|
||||
#ifdef __NVIC_PRIO_BITS
|
||||
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||
#else
|
||||
#error "This port requires __NVIC_PRIO_BITS to be defined"
|
||||
#endif
|
||||
|
||||
/* Access to current system core clock is required only if we are ticking the system by systimer */
|
||||
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
||||
#include <stdint.h>
|
||||
extern uint32_t SystemCoreClock;
|
||||
#endif
|
||||
/* Access to current system core clock is required only if we are ticking the system by systimer */
|
||||
#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK)
|
||||
#include <stdint.h>
|
||||
extern uint32_t SystemCoreClock;
|
||||
#endif
|
||||
#endif /* !assembler */
|
||||
|
||||
/** Implementation note: Use this with caution and set this to 1 ONLY for debugging
|
||||
* ----------------------------------------------------------
|
||||
* Set the value of configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to below for enabling or disabling RTOS tick auto correction:
|
||||
* 0. This is default. If the RTC tick interrupt is masked for more than 1 tick by higher priority interrupts, then most likely
|
||||
* one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed
|
||||
* for the RTOS internal timers to be more accurate.
|
||||
* 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging
|
||||
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the auto-corrections of
|
||||
* RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go out of sync but could be
|
||||
* convenient for debugging.
|
||||
*/
|
||||
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
|
||||
* Set the value of configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to below for enabling or disabling RTOS tick auto correction:
|
||||
* 0. This is default. If the RTC tick interrupt is masked for more than 1 tick by higher priority interrupts, then most likely
|
||||
* one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed
|
||||
* for the RTOS internal timers to be more accurate.
|
||||
* 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when debugging
|
||||
* the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the
|
||||
* auto-corrections of RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and RTOS go
|
||||
* out of sync but could be convenient for debugging.
|
||||
*/
|
||||
#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
|
@ -8,11 +8,13 @@ namespace Pinetime {
|
||||
static constexpr uint32_t Major() {return major;}
|
||||
static constexpr uint32_t Minor() {return minor;}
|
||||
static constexpr uint32_t Patch() {return patch;}
|
||||
static constexpr const char* GitCommitHash() {return commitHash;}
|
||||
static constexpr const char* VersionString() {return versionString;}
|
||||
private:
|
||||
static constexpr uint32_t major = @PROJECT_VERSION_MAJOR@;
|
||||
static constexpr uint32_t minor = @PROJECT_VERSION_MINOR@;
|
||||
static constexpr uint32_t patch = @PROJECT_VERSION_PATCH@;
|
||||
static constexpr const char* commitHash = "@PROJECT_GIT_COMMIT_HASH@";
|
||||
static constexpr const char* versionString = "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@";
|
||||
};
|
||||
}
|
@ -7,33 +7,32 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
Battery *Battery::instance = nullptr;
|
||||
Battery* Battery::instance = nullptr;
|
||||
|
||||
Battery::Battery() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
void Battery::Init() {
|
||||
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||
}
|
||||
|
||||
void Battery::Update() {
|
||||
|
||||
isCharging = !nrf_gpio_pin_read(chargingPin);
|
||||
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
|
||||
|
||||
if ( isReading ) return;
|
||||
|
||||
if (isReading)
|
||||
return;
|
||||
// Non blocking read
|
||||
samples = 0;
|
||||
isReading = true;
|
||||
SaadcInit();
|
||||
SaadcInit();
|
||||
|
||||
nrfx_saadc_sample();
|
||||
|
||||
nrfx_saadc_sample();
|
||||
}
|
||||
|
||||
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const *event) {
|
||||
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) {
|
||||
instance->SaadcEventHandler(event);
|
||||
}
|
||||
|
||||
@ -41,48 +40,44 @@ void Battery::SaadcInit() {
|
||||
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
|
||||
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
|
||||
|
||||
nrf_saadc_channel_config_t adcChannelConfig = {
|
||||
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.gain = NRF_SAADC_GAIN1_5,
|
||||
.reference = NRF_SAADC_REFERENCE_INTERNAL,
|
||||
.acq_time = NRF_SAADC_ACQTIME_3US,
|
||||
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
||||
.burst = NRF_SAADC_BURST_ENABLED,
|
||||
.pin_p = batteryVoltageAdcInput,
|
||||
.pin_n = NRF_SAADC_INPUT_DISABLED
|
||||
};
|
||||
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.gain = NRF_SAADC_GAIN1_5,
|
||||
.reference = NRF_SAADC_REFERENCE_INTERNAL,
|
||||
.acq_time = NRF_SAADC_ACQTIME_3US,
|
||||
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
||||
.burst = NRF_SAADC_BURST_ENABLED,
|
||||
.pin_p = batteryVoltageAdcInput,
|
||||
.pin_n = NRF_SAADC_INPUT_DISABLED};
|
||||
APP_ERROR_CHECK(nrfx_saadc_channel_init(0, &adcChannelConfig));
|
||||
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
||||
|
||||
}
|
||||
|
||||
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) {
|
||||
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
|
||||
|
||||
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
|
||||
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
|
||||
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
|
||||
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
|
||||
|
||||
if (p_event->type == NRFX_SAADC_EVT_DONE) {
|
||||
|
||||
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
||||
if (p_event->type == NRFX_SAADC_EVT_DONE) {
|
||||
|
||||
voltage = (static_cast<float>(p_event->data.done.p_buffer[0]) * 2.04f) / (1024 / 3.0f);
|
||||
voltage = roundf(voltage * 100) / 100;
|
||||
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
||||
|
||||
percentRemaining = static_cast<int>(((voltage - battery_min) / (battery_max - battery_min)) * 100);
|
||||
voltage = (static_cast<float>(p_event->data.done.p_buffer[0]) * 2.04f) / (1024 / 3.0f);
|
||||
voltage = roundf(voltage * 100) / 100;
|
||||
|
||||
percentRemaining = std::max(percentRemaining, 0);
|
||||
percentRemaining = std::min(percentRemaining, 100);
|
||||
percentRemaining = static_cast<int>(((voltage - battery_min) / (battery_max - battery_min)) * 100);
|
||||
|
||||
percentRemainingBuffer.insert(percentRemaining);
|
||||
percentRemaining = std::max(percentRemaining, 0);
|
||||
percentRemaining = std::min(percentRemaining, 100);
|
||||
|
||||
samples++;
|
||||
if ( samples > percentRemainingSamples ) {
|
||||
nrfx_saadc_uninit();
|
||||
isReading = false;
|
||||
} else {
|
||||
nrfx_saadc_sample();
|
||||
}
|
||||
percentRemainingBuffer.insert(percentRemaining);
|
||||
|
||||
samples++;
|
||||
if (samples > percentRemainingSamples) {
|
||||
nrfx_saadc_uninit();
|
||||
isReading = false;
|
||||
} else {
|
||||
nrfx_saadc_sample();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,18 +7,18 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
|
||||
/** A simple circular buffer that can be used to average
|
||||
out the sensor values. The total capacity of the CircBuffer
|
||||
/** A simple circular buffer that can be used to average
|
||||
out the sensor values. The total capacity of the CircBuffer
|
||||
is given as the template parameter N.
|
||||
*/
|
||||
template <int N>
|
||||
class CircBuffer {
|
||||
*/
|
||||
template <int N> class CircBuffer {
|
||||
public:
|
||||
CircBuffer() : arr{}, sz{}, cap{N}, head{} {}
|
||||
CircBuffer() : arr {}, sz {}, cap {N}, head {} {
|
||||
}
|
||||
/**
|
||||
insert member function overwrites the next data to the current
|
||||
insert member function overwrites the next data to the current
|
||||
HEAD and moves the HEAD to the newly inserted value.
|
||||
*/
|
||||
*/
|
||||
void insert(const int num) {
|
||||
head %= cap;
|
||||
arr[head++] = num;
|
||||
@ -34,49 +34,56 @@ namespace Pinetime {
|
||||
|
||||
private:
|
||||
std::array<int, N> arr; /**< internal array used to store the values*/
|
||||
uint8_t sz; /**< The current size of the array.*/
|
||||
uint8_t cap; /**< Total capacity of the CircBuffer.*/
|
||||
uint8_t head; /**< The current head of the CircBuffer*/
|
||||
uint8_t sz; /**< The current size of the array.*/
|
||||
uint8_t cap; /**< Total capacity of the CircBuffer.*/
|
||||
uint8_t head; /**< The current head of the CircBuffer*/
|
||||
};
|
||||
|
||||
class Battery {
|
||||
public:
|
||||
public:
|
||||
Battery();
|
||||
|
||||
Battery();
|
||||
void Init();
|
||||
void Update();
|
||||
|
||||
void Init();
|
||||
void Update();
|
||||
|
||||
int PercentRemaining() const { return percentRemainingBuffer.GetAverage(); }
|
||||
int PercentRemaining() const {
|
||||
return percentRemainingBuffer.GetAverage();
|
||||
}
|
||||
|
||||
float Voltage() const { return voltage; }
|
||||
float Voltage() const {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
bool IsCharging() const { return isCharging; }
|
||||
bool IsPowerPresent() const { return isPowerPresent; }
|
||||
bool IsCharging() const {
|
||||
return isCharging;
|
||||
}
|
||||
bool IsPowerPresent() const {
|
||||
return isPowerPresent;
|
||||
}
|
||||
|
||||
private:
|
||||
static Battery *instance;
|
||||
nrf_saadc_value_t saadc_value;
|
||||
|
||||
static constexpr uint8_t percentRemainingSamples = 5;
|
||||
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
|
||||
private:
|
||||
static Battery* instance;
|
||||
nrf_saadc_value_t saadc_value;
|
||||
|
||||
static constexpr uint32_t chargingPin = 12;
|
||||
static constexpr uint32_t powerPresentPin = 19;
|
||||
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
||||
float voltage = 0.0f;
|
||||
int percentRemaining = -1;
|
||||
static constexpr uint8_t percentRemainingSamples = 5;
|
||||
CircBuffer<percentRemainingSamples> percentRemainingBuffer {};
|
||||
|
||||
bool isCharging = false;
|
||||
bool isPowerPresent = false;
|
||||
|
||||
void SaadcInit();
|
||||
static constexpr uint32_t chargingPin = 12;
|
||||
static constexpr uint32_t powerPresentPin = 19;
|
||||
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
||||
float voltage = 0.0f;
|
||||
int percentRemaining = -1;
|
||||
|
||||
void SaadcEventHandler(nrfx_saadc_evt_t const * p_event);
|
||||
static void adcCallbackStatic(nrfx_saadc_evt_t const *event);
|
||||
bool isCharging = false;
|
||||
bool isPowerPresent = false;
|
||||
|
||||
bool isReading = false;
|
||||
uint8_t samples = 0;
|
||||
void SaadcInit();
|
||||
|
||||
void SaadcEventHandler(nrfx_saadc_evt_t const* p_event);
|
||||
static void adcCallbackStatic(nrfx_saadc_evt_t const* event);
|
||||
|
||||
bool isReading = false;
|
||||
uint8_t samples = 0;
|
||||
};
|
||||
}
|
||||
}
|
@ -12,50 +12,42 @@ constexpr ble_uuid16_t AlertNotificationClient::unreadAlertStatusUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
|
||||
|
||||
namespace {
|
||||
int
|
||||
OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error* error,
|
||||
const struct ble_gatt_chr* chr,
|
||||
void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(
|
||||
uint16_t conn_handle, const struct ble_gatt_error* error, uint16_t chr_val_handle, const struct ble_gatt_dsc* dsc, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
||||
}
|
||||
|
||||
int NewAlertSubcribeCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnNewAlertSubcribe(conn_handle, error, attr);
|
||||
}
|
||||
}
|
||||
|
||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
||||
systemTask{systemTask}, notificationManager{notificationManager} {
|
||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager)
|
||||
: systemTask {systemTask}, notificationManager {notificationManager} {
|
||||
}
|
||||
|
||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_svc *service) {
|
||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle,
|
||||
OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle, OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("ANS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
@ -63,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
|
||||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ansServiceUuid), &service->uuid.u) == 0) {
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
ansStartHandle = service->start_handle;
|
||||
ansEndHandle = service->end_handle;
|
||||
@ -72,8 +64,9 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
|
||||
return false;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
const ble_gatt_chr* characteristic) {
|
||||
if (error->status != 0 && error->status != BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery ERROR");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
@ -83,41 +76,34 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection
|
||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery complete");
|
||||
if (isCharacteristicDiscovered) {
|
||||
ble_gattc_disc_all_dscs(connectionHandle,
|
||||
newAlertHandle, ansEndHandle,
|
||||
OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||
ble_gattc_disc_all_dscs(connectionHandle, newAlertHandle, ansEndHandle, OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||
} else
|
||||
onServiceDiscovered(connectionHandle);
|
||||
} else {
|
||||
if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
|
||||
supportedNewAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
|
||||
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
|
||||
newAlertHandle = characteristic->val_handle;
|
||||
newAlertDefHandle = characteristic->def_handle;
|
||||
isCharacteristicDiscovered = true;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
|
||||
unreadAlertStatusHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||
} else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
|
||||
controlPointHandle = characteristic->val_handle;
|
||||
} else NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
} else
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
ble_gatt_attr *attribute) {
|
||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) {
|
||||
if (error->status == 0) {
|
||||
NRF_LOG_INFO("ANS New alert subscribe OK");
|
||||
} else {
|
||||
@ -128,12 +114,12 @@ int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc *descriptor) {
|
||||
const ble_gatt_dsc* descriptor) {
|
||||
if (error->status == 0) {
|
||||
if (characteristicValueHandle == newAlertHandle &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &descriptor->uuid.u)) {
|
||||
if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) {
|
||||
if (newAlertDescriptorHandle == 0) {
|
||||
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
|
||||
newAlertDescriptorHandle = descriptor->handle;
|
||||
@ -151,16 +137,17 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AlertNotificationClient::OnNotification(ble_gap_event *event) {
|
||||
void AlertNotificationClient::OnNotification(ble_gap_event* event) {
|
||||
if (event->notify_rx.attr_handle == newAlertHandle) {
|
||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||
constexpr size_t headerSize = 3;
|
||||
const auto maxMessageSize{NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
||||
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize {maxMessageSize + headerSize};
|
||||
|
||||
// Ignore notifications with empty message
|
||||
const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||
if(packetLen <= headerSize) return;
|
||||
if (packetLen <= headerSize)
|
||||
return;
|
||||
|
||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||
|
@ -19,68 +19,52 @@ namespace Pinetime {
|
||||
class NotificationManager;
|
||||
|
||||
class AlertNotificationClient : public BleClient {
|
||||
public:
|
||||
explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
public:
|
||||
explicit AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager);
|
||||
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
||||
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
|
||||
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
||||
void OnNotification(ble_gap_event *event);
|
||||
void Reset();
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
|
||||
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc* descriptor);
|
||||
void OnNotification(ble_gap_event* event);
|
||||
void Reset();
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
private:
|
||||
static constexpr uint16_t ansServiceId{0x1811};
|
||||
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
|
||||
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
|
||||
static constexpr uint16_t newAlertId = 0x2a46;
|
||||
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
|
||||
static constexpr uint16_t controlPointId = 0x2a44;
|
||||
private:
|
||||
static constexpr uint16_t ansServiceId {0x1811};
|
||||
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
|
||||
static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48;
|
||||
static constexpr uint16_t newAlertId = 0x2a46;
|
||||
static constexpr uint16_t unreadAlertStatusId = 0x2a45;
|
||||
static constexpr uint16_t controlPointId = 0x2a44;
|
||||
|
||||
static constexpr ble_uuid16_t ansServiceUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = ansServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = supportedNewAlertCategoryId
|
||||
};
|
||||
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = supportedUnreadAlertCategoryId
|
||||
};
|
||||
static constexpr ble_uuid16_t newAlertUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = newAlertId
|
||||
};
|
||||
static constexpr ble_uuid16_t unreadAlertStatusUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = unreadAlertStatusId
|
||||
};
|
||||
static constexpr ble_uuid16_t controlPointUuid{
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = controlPointId
|
||||
};
|
||||
static constexpr ble_uuid16_t ansServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansServiceId};
|
||||
static constexpr ble_uuid16_t supportedNewAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, .value = supportedNewAlertCategoryId};
|
||||
static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = supportedUnreadAlertCategoryId};
|
||||
static constexpr ble_uuid16_t newAlertUuid {.u {.type = BLE_UUID_TYPE_16}, .value = newAlertId};
|
||||
static constexpr ble_uuid16_t unreadAlertStatusUuid {.u {.type = BLE_UUID_TYPE_16}, .value = unreadAlertStatusId};
|
||||
static constexpr ble_uuid16_t controlPointUuid {.u {.type = BLE_UUID_TYPE_16}, .value = controlPointId};
|
||||
|
||||
uint16_t ansStartHandle = 0;
|
||||
uint16_t ansEndHandle = 0;
|
||||
uint16_t supportedNewAlertCategoryHandle = 0;
|
||||
uint16_t supportedUnreadAlertCategoryHandle = 0;
|
||||
uint16_t newAlertHandle = 0;
|
||||
uint16_t newAlertDescriptorHandle = 0;
|
||||
uint16_t newAlertDefHandle = 0;
|
||||
uint16_t unreadAlertStatusHandle = 0;
|
||||
uint16_t controlPointHandle = 0;
|
||||
bool isDiscovered = false;
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
bool isCharacteristicDiscovered = false;
|
||||
bool isDescriptorFound = false;
|
||||
uint16_t ansStartHandle = 0;
|
||||
uint16_t ansEndHandle = 0;
|
||||
uint16_t supportedNewAlertCategoryHandle = 0;
|
||||
uint16_t supportedUnreadAlertCategoryHandle = 0;
|
||||
uint16_t newAlertHandle = 0;
|
||||
uint16_t newAlertDescriptorHandle = 0;
|
||||
uint16_t newAlertDefHandle = 0;
|
||||
uint16_t unreadAlertStatusHandle = 0;
|
||||
uint16_t controlPointHandle = 0;
|
||||
bool isDiscovered = false;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
bool isCharacteristicDiscovered = false;
|
||||
bool isDescriptorFound = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,7 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationService::ansCharUuid;
|
||||
constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid;
|
||||
|
||||
|
||||
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto anService = static_cast<AlertNotificationService*>(arg);
|
||||
return anService->OnAlert(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
@ -26,62 +25,52 @@ void AlertNotificationService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
AlertNotificationService::AlertNotificationService ( System::SystemTask& systemTask, NotificationManager& notificationManager )
|
||||
: characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &ansCharUuid,
|
||||
.access_cb = AlertNotificationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) ¬ificationEventUuid,
|
||||
.access_cb = AlertNotificationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &ansUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}, systemTask{systemTask}, notificationManager{notificationManager} {
|
||||
AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager)
|
||||
: characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid,
|
||||
.access_cb = AlertNotificationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE},
|
||||
{.uuid = (ble_uuid_t*) ¬ificationEventUuid,
|
||||
.access_cb = AlertNotificationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &ansUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
},
|
||||
systemTask {systemTask},
|
||||
notificationManager {notificationManager} {
|
||||
}
|
||||
|
||||
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||
constexpr size_t headerSize = 3;
|
||||
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
||||
const auto maxBufferSize {maxMessageSize + headerSize};
|
||||
|
||||
// Ignore notifications with empty message
|
||||
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
|
||||
if(packetLen <= headerSize) return 0;
|
||||
if (packetLen <= headerSize)
|
||||
return 0;
|
||||
|
||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize-headerSize));
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||
Categories category;
|
||||
|
||||
NotificationManager::Notification notif;
|
||||
os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data());
|
||||
os_mbuf_copydata(ctxt->om, headerSize, messageSize - 1, notif.message.data());
|
||||
os_mbuf_copydata(ctxt->om, 0, 1, &category);
|
||||
notif.message[messageSize-1] = '\0';
|
||||
notif.message[messageSize - 1] = '\0';
|
||||
notif.size = messageSize;
|
||||
|
||||
// TODO convert all ANS categories to NotificationController categories
|
||||
switch(category) {
|
||||
switch (category) {
|
||||
case Categories::Call:
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall;
|
||||
break;
|
||||
@ -99,7 +88,7 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle
|
||||
|
||||
void AlertNotificationService::AcceptIncomingCall() {
|
||||
auto response = IncomingCallResponses::Answer;
|
||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
@ -112,7 +101,7 @@ void AlertNotificationService::AcceptIncomingCall() {
|
||||
|
||||
void AlertNotificationService::RejectIncomingCall() {
|
||||
auto response = IncomingCallResponses::Reject;
|
||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
@ -125,7 +114,7 @@ void AlertNotificationService::RejectIncomingCall() {
|
||||
|
||||
void AlertNotificationService::MuteIncomingCall() {
|
||||
auto response = IncomingCallResponses::Mute;
|
||||
auto *om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
auto* om = ble_hs_mbuf_from_flat(&response, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
|
@ -7,8 +7,9 @@
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
//00020001-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00}
|
||||
// 00020001-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NOTIFICATION_EVENT_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
@ -19,64 +20,49 @@ namespace Pinetime {
|
||||
class NotificationManager;
|
||||
|
||||
class AlertNotificationService {
|
||||
public:
|
||||
AlertNotificationService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
void Init();
|
||||
public:
|
||||
AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
|
||||
void Init();
|
||||
|
||||
int OnAlert(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
void AcceptIncomingCall();
|
||||
void RejectIncomingCall();
|
||||
void MuteIncomingCall();
|
||||
void AcceptIncomingCall();
|
||||
void RejectIncomingCall();
|
||||
void MuteIncomingCall();
|
||||
|
||||
enum class IncomingCallResponses : uint8_t {
|
||||
Reject = 0x00,
|
||||
Answer = 0x01,
|
||||
Mute = 0x02
|
||||
};
|
||||
enum class IncomingCallResponses : uint8_t { Reject = 0x00, Answer = 0x01, Mute = 0x02 };
|
||||
|
||||
private:
|
||||
enum class Categories : uint8_t {
|
||||
SimpleAlert = 0x00,
|
||||
Email = 0x01,
|
||||
News = 0x02,
|
||||
Call = 0x03,
|
||||
MissedCall = 0x04,
|
||||
MmsSms = 0x05,
|
||||
VoiceMail = 0x06,
|
||||
Schedule = 0x07,
|
||||
HighPrioritizedAlert = 0x08,
|
||||
InstantMessage = 0x09,
|
||||
All = 0xff
|
||||
};
|
||||
private:
|
||||
enum class Categories : uint8_t {
|
||||
SimpleAlert = 0x00,
|
||||
Email = 0x01,
|
||||
News = 0x02,
|
||||
Call = 0x03,
|
||||
MissedCall = 0x04,
|
||||
MmsSms = 0x05,
|
||||
VoiceMail = 0x06,
|
||||
Schedule = 0x07,
|
||||
HighPrioritizedAlert = 0x08,
|
||||
InstantMessage = 0x09,
|
||||
All = 0xff
|
||||
};
|
||||
|
||||
static constexpr uint16_t ansId {0x1811};
|
||||
static constexpr uint16_t ansCharId {0x2a46};
|
||||
static constexpr uint16_t ansId {0x1811};
|
||||
static constexpr uint16_t ansCharId {0x2a46};
|
||||
|
||||
static constexpr ble_uuid16_t ansUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ansId
|
||||
};
|
||||
static constexpr ble_uuid16_t ansUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansId};
|
||||
|
||||
static constexpr ble_uuid16_t ansCharUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ansCharId
|
||||
};
|
||||
static constexpr ble_uuid16_t ansCharUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansCharId};
|
||||
|
||||
static constexpr ble_uuid128_t notificationEventUuid {
|
||||
.u { .type = BLE_UUID_TYPE_128 },
|
||||
.value = NOTIFICATION_EVENT_SERVICE_UUID_BASE
|
||||
};
|
||||
static constexpr ble_uuid128_t notificationEventUuid {.u {.type = BLE_UUID_TYPE_128}, .value = NOTIFICATION_EVENT_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
NotificationManager ¬ificationManager;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
NotificationManager& notificationManager;
|
||||
|
||||
uint16_t eventHandle;
|
||||
uint16_t eventHandle;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -7,39 +7,26 @@ using namespace Pinetime::Controllers;
|
||||
constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid;
|
||||
constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid;
|
||||
|
||||
|
||||
|
||||
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* batteryInformationService = static_cast<BatteryInformationService*>(arg);
|
||||
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) :
|
||||
batteryController{batteryController},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &batteryLevelUuid,
|
||||
.access_cb = BatteryInformationServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &batteryLevelHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &batteryInformationServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
|
||||
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
|
||||
: batteryController {batteryController},
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
|
||||
.access_cb = BatteryInformationServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &batteryLevelHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
void BatteryInformationService::Init() {
|
||||
@ -51,9 +38,10 @@ void BatteryInformationService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == batteryLevelHandle) {
|
||||
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle,
|
||||
uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == batteryLevelHandle) {
|
||||
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
|
||||
static uint8_t batteryValue = batteryController.PercentRemaining();
|
||||
int res = os_mbuf_append(context->om, &batteryValue, 1);
|
||||
|
@ -12,33 +12,25 @@ namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Battery;
|
||||
class BatteryInformationService {
|
||||
public:
|
||||
BatteryInformationService(Controllers::Battery& batteryController);
|
||||
void Init();
|
||||
public:
|
||||
BatteryInformationService(Controllers::Battery& batteryController);
|
||||
void Init();
|
||||
|
||||
int
|
||||
OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
|
||||
private:
|
||||
Controllers::Battery& batteryController;
|
||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||
static constexpr uint16_t batteryLevelId {0x2A19};
|
||||
private:
|
||||
Controllers::Battery& batteryController;
|
||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||
static constexpr uint16_t batteryLevelId {0x2A19};
|
||||
|
||||
static constexpr ble_uuid16_t batteryInformationServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = batteryInformationServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t batteryInformationServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryInformationServiceId};
|
||||
|
||||
static constexpr ble_uuid16_t batteryLevelUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = batteryLevelId
|
||||
};
|
||||
static constexpr ble_uuid16_t batteryLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = batteryLevelId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t batteryLevelHandle;
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t batteryLevelHandle;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@
|
||||
#include <functional>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers{
|
||||
namespace Controllers {
|
||||
class BleClient {
|
||||
public:
|
||||
virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0;
|
||||
public:
|
||||
virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0;
|
||||
};
|
||||
}
|
||||
}
|
@ -25,5 +25,3 @@ void Ble::FirmwareUpdateTotalBytes(uint32_t totalBytes) {
|
||||
void Ble::FirmwareUpdateCurrentBytes(uint32_t currentBytes) {
|
||||
firmwareUpdateCurrentBytes = currentBytes;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,39 +6,57 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Ble {
|
||||
public:
|
||||
using BleAddress = std::array<uint8_t, 6>;
|
||||
enum class FirmwareUpdateStates {Idle, Running, Validated, Error};
|
||||
enum class AddressTypes { Public, Random };
|
||||
public:
|
||||
using BleAddress = std::array<uint8_t, 6>;
|
||||
enum class FirmwareUpdateStates { Idle, Running, Validated, Error };
|
||||
enum class AddressTypes { Public, Random };
|
||||
|
||||
Ble() = default;
|
||||
bool IsConnected() const {return isConnected;}
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
Ble() = default;
|
||||
bool IsConnected() const {
|
||||
return isConnected;
|
||||
}
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
void StartFirmwareUpdate();
|
||||
void StopFirmwareUpdate();
|
||||
void FirmwareUpdateTotalBytes(uint32_t totalBytes);
|
||||
void FirmwareUpdateCurrentBytes(uint32_t currentBytes);
|
||||
void State(FirmwareUpdateStates state) { firmwareUpdateState = state; }
|
||||
void StartFirmwareUpdate();
|
||||
void StopFirmwareUpdate();
|
||||
void FirmwareUpdateTotalBytes(uint32_t totalBytes);
|
||||
void FirmwareUpdateCurrentBytes(uint32_t currentBytes);
|
||||
void State(FirmwareUpdateStates state) {
|
||||
firmwareUpdateState = state;
|
||||
}
|
||||
|
||||
bool IsFirmwareUpdating() const { return isFirmwareUpdating; }
|
||||
uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; }
|
||||
uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; }
|
||||
FirmwareUpdateStates State() const { return firmwareUpdateState; }
|
||||
bool IsFirmwareUpdating() const {
|
||||
return isFirmwareUpdating;
|
||||
}
|
||||
uint32_t FirmwareUpdateTotalBytes() const {
|
||||
return firmwareUpdateTotalBytes;
|
||||
}
|
||||
uint32_t FirmwareUpdateCurrentBytes() const {
|
||||
return firmwareUpdateCurrentBytes;
|
||||
}
|
||||
FirmwareUpdateStates State() const {
|
||||
return firmwareUpdateState;
|
||||
}
|
||||
|
||||
void Address(BleAddress&& addr) { address = addr; }
|
||||
const BleAddress& Address() const { return address; }
|
||||
void AddressType(AddressTypes t) { addressType = t;}
|
||||
private:
|
||||
bool isConnected = false;
|
||||
bool isFirmwareUpdating = false;
|
||||
uint32_t firmwareUpdateTotalBytes = 0;
|
||||
uint32_t firmwareUpdateCurrentBytes = 0;
|
||||
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
|
||||
BleAddress address;
|
||||
AddressTypes addressType;
|
||||
void Address(BleAddress&& addr) {
|
||||
address = addr;
|
||||
}
|
||||
const BleAddress& Address() const {
|
||||
return address;
|
||||
}
|
||||
void AddressType(AddressTypes t) {
|
||||
addressType = t;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isConnected = false;
|
||||
bool isFirmwareUpdating = false;
|
||||
uint32_t firmwareUpdateTotalBytes = 0;
|
||||
uint32_t firmwareUpdateCurrentBytes = 0;
|
||||
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
|
||||
BleAddress address;
|
||||
AddressTypes addressType;
|
||||
};
|
||||
}
|
||||
}
|
@ -9,39 +9,37 @@ constexpr ble_uuid16_t CurrentTimeClient::ctsServiceUuid;
|
||||
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||
|
||||
namespace {
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error* error,
|
||||
const struct ble_gatt_chr* chr,
|
||||
void* arg) {
|
||||
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) {
|
||||
auto client = static_cast<CurrentTimeClient*>(arg);
|
||||
return client->OnCurrentTimeReadResult(conn_handle, error, attr);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentTimeClient::CurrentTimeClient(DateTime &dateTimeController) : dateTimeController{dateTimeController} {
|
||||
|
||||
CurrentTimeClient::CurrentTimeClient(DateTime& dateTimeController) : dateTimeController {dateTimeController} {
|
||||
}
|
||||
|
||||
void CurrentTimeClient::Init() {
|
||||
|
||||
}
|
||||
|
||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_svc *service) {
|
||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("CTS found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle,
|
||||
OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle, OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("CTS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
@ -49,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
|
||||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ctsServiceUuid), &service->uuid.u) == 0) {
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
isDiscovered = true;
|
||||
ctsStartHandle = service->start_handle;
|
||||
@ -59,8 +57,9 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
|
||||
return false;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
|
||||
const ble_gatt_error* error,
|
||||
const ble_gatt_chr* characteristic) {
|
||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isCharacteristicDiscovered) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time");
|
||||
@ -73,8 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||
if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
isCharacteristicDiscovered = true;
|
||||
currentTimeHandle = characteristic->val_handle;
|
||||
@ -82,17 +80,15 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_attr *attribute) {
|
||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute) {
|
||||
if (error->status == 0) {
|
||||
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
||||
CtsData result;
|
||||
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
||||
result.month, result.dayofmonth,
|
||||
result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
NRF_LOG_INFO(
|
||||
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(
|
||||
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
} else {
|
||||
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
||||
}
|
||||
|
@ -8,54 +8,51 @@
|
||||
#include "BleClient.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class DateTime;
|
||||
namespace Controllers {
|
||||
class DateTime;
|
||||
|
||||
class CurrentTimeClient : public BleClient {
|
||||
public:
|
||||
explicit CurrentTimeClient(DateTime& dateTimeController);
|
||||
void Init();
|
||||
void Reset();
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute);
|
||||
static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; }
|
||||
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; }
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
class CurrentTimeClient : public BleClient {
|
||||
public:
|
||||
explicit CurrentTimeClient(DateTime& dateTimeController);
|
||||
void Init();
|
||||
void Reset();
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute);
|
||||
static constexpr const ble_uuid16_t* Uuid() {
|
||||
return &CurrentTimeClient::ctsServiceUuid;
|
||||
}
|
||||
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() {
|
||||
return &CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||
}
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
private:
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t dayofmonth;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t millis;
|
||||
uint8_t reason;
|
||||
} CtsData;
|
||||
private:
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t dayofmonth;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t millis;
|
||||
uint8_t reason;
|
||||
} CtsData;
|
||||
|
||||
static constexpr uint16_t ctsServiceId {0x1805};
|
||||
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
|
||||
static constexpr uint16_t ctsServiceId {0x1805};
|
||||
static constexpr uint16_t currentTimeCharacteristicId {0x2a2b};
|
||||
|
||||
static constexpr ble_uuid16_t ctsServiceUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ctsServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = currentTimeCharacteristicId
|
||||
};
|
||||
static constexpr ble_uuid16_t ctsServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsServiceId};
|
||||
static constexpr ble_uuid16_t currentTimeCharacteristicUuid {.u {.type = BLE_UUID_TYPE_16}, .value = currentTimeCharacteristicId};
|
||||
|
||||
DateTime& dateTimeController;
|
||||
bool isDiscovered = false;
|
||||
uint16_t ctsStartHandle;
|
||||
uint16_t ctsEndHandle;
|
||||
DateTime& dateTimeController;
|
||||
bool isDiscovered = false;
|
||||
uint16_t ctsStartHandle;
|
||||
uint16_t ctsEndHandle;
|
||||
|
||||
bool isCharacteristicDiscovered = false;
|
||||
uint16_t currentTimeHandle;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
};
|
||||
}
|
||||
bool isCharacteristicDiscovered = false;
|
||||
uint16_t currentTimeHandle;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
};
|
||||
}
|
||||
}
|
@ -7,8 +7,7 @@ using namespace Pinetime::Controllers;
|
||||
constexpr ble_uuid16_t CurrentTimeService::ctsUuid;
|
||||
constexpr ble_uuid16_t CurrentTimeService::ctChrUuid;
|
||||
|
||||
|
||||
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto cts = static_cast<CurrentTimeService*>(arg);
|
||||
return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
@ -22,22 +21,19 @@ void CurrentTimeService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
|
||||
NRF_LOG_INFO("Setting time...");
|
||||
NRF_LOG_INFO("Setting time...");
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
CtsData result;
|
||||
os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
|
||||
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
||||
result.month, result.dayofmonth,
|
||||
result.hour, result.minute, result.second);
|
||||
NRF_LOG_INFO(
|
||||
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||
|
||||
m_dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
m_dateTimeController.SetTime(
|
||||
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
CtsData currentDateTime;
|
||||
@ -49,39 +45,26 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
|
||||
currentDateTime.second = m_dateTimeController.Seconds();
|
||||
currentDateTime.millis = 0;
|
||||
|
||||
|
||||
int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData));
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CurrentTimeService::CurrentTimeService(DateTime &dateTimeController) :
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &ctChrUuid,
|
||||
.access_cb = CTSCallback,
|
||||
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &ctsUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}, m_dateTimeController{dateTimeController} {
|
||||
CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
|
||||
: characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid,
|
||||
.access_cb = CTSCallback,
|
||||
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &ctsUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
},
|
||||
m_dateTimeController {dateTimeController} {
|
||||
}
|
||||
|
||||
|
@ -12,42 +12,35 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class CurrentTimeService {
|
||||
public:
|
||||
CurrentTimeService(DateTime &dateTimeController);
|
||||
void Init();
|
||||
public:
|
||||
CurrentTimeService(DateTime& dateTimeController);
|
||||
void Init();
|
||||
|
||||
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t ctsId {0x1805};
|
||||
static constexpr uint16_t ctsCharId {0x2a2b};
|
||||
private:
|
||||
static constexpr uint16_t ctsId {0x1805};
|
||||
static constexpr uint16_t ctsCharId {0x2a2b};
|
||||
|
||||
static constexpr ble_uuid16_t ctsUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ctsId
|
||||
};
|
||||
static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId};
|
||||
|
||||
static constexpr ble_uuid16_t ctChrUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = ctsCharId
|
||||
};
|
||||
static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t dayofmonth;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t millis;
|
||||
uint8_t reason;
|
||||
} CtsData;
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t dayofmonth;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t millis;
|
||||
uint8_t reason;
|
||||
} CtsData;
|
||||
|
||||
DateTime &m_dateTimeController;
|
||||
DateTime& m_dateTimeController;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,7 @@ constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid;
|
||||
constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid;
|
||||
constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid;
|
||||
|
||||
|
||||
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto deviceInformationService = static_cast<DeviceInformationService*>(arg);
|
||||
return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
@ -25,10 +24,8 @@ void DeviceInformationService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
|
||||
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
const char *str;
|
||||
int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
const char* str;
|
||||
|
||||
switch (ble_uuid_u16(ctxt->chr->uuid)) {
|
||||
case manufacturerNameId:
|
||||
@ -57,60 +54,49 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
DeviceInformationService::DeviceInformationService() :
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &manufacturerNameUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &modelNumberUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &serialNumberUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &fwRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &hwRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &swRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &deviceInfoUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}
|
||||
{
|
||||
|
||||
DeviceInformationService::DeviceInformationService()
|
||||
: characteristicDefinition {{
|
||||
.uuid = (ble_uuid_t*) &manufacturerNameUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &modelNumberUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &serialNumberUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &fwRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &hwRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &swRevisionUuid,
|
||||
.access_cb = DeviceInformationCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &deviceInfoUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
|
@ -9,69 +9,44 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class DeviceInformationService {
|
||||
public:
|
||||
DeviceInformationService();
|
||||
void Init();
|
||||
public:
|
||||
DeviceInformationService();
|
||||
void Init();
|
||||
|
||||
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t deviceInfoId {0x180a};
|
||||
static constexpr uint16_t manufacturerNameId {0x2a29};
|
||||
static constexpr uint16_t modelNumberId {0x2a24};
|
||||
static constexpr uint16_t serialNumberId {0x2a25};
|
||||
static constexpr uint16_t fwRevisionId {0x2a26};
|
||||
static constexpr uint16_t hwRevisionId {0x2a27};
|
||||
static constexpr uint16_t swRevisionId {0x2a28};
|
||||
private:
|
||||
static constexpr uint16_t deviceInfoId {0x180a};
|
||||
static constexpr uint16_t manufacturerNameId {0x2a29};
|
||||
static constexpr uint16_t modelNumberId {0x2a24};
|
||||
static constexpr uint16_t serialNumberId {0x2a25};
|
||||
static constexpr uint16_t fwRevisionId {0x2a26};
|
||||
static constexpr uint16_t hwRevisionId {0x2a27};
|
||||
static constexpr uint16_t swRevisionId {0x2a28};
|
||||
|
||||
static constexpr const char* manufacturerName = "PINE64";
|
||||
static constexpr const char* modelNumber = "PineTime";
|
||||
static constexpr const char* hwRevision = "1.0.0";
|
||||
static constexpr const char* serialNumber = "0";
|
||||
static constexpr const char* fwRevision = Version::VersionString();
|
||||
static constexpr const char* swRevision = "InfiniTime";
|
||||
static constexpr const char* manufacturerName = "PINE64";
|
||||
static constexpr const char* modelNumber = "PineTime";
|
||||
static constexpr const char* hwRevision = "1.0.0";
|
||||
static constexpr const char* serialNumber = "0";
|
||||
static constexpr const char* fwRevision = Version::VersionString();
|
||||
static constexpr const char* swRevision = "InfiniTime";
|
||||
|
||||
static constexpr ble_uuid16_t deviceInfoUuid {.u {.type = BLE_UUID_TYPE_16}, .value = deviceInfoId};
|
||||
|
||||
static constexpr ble_uuid16_t deviceInfoUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = deviceInfoId
|
||||
};
|
||||
static constexpr ble_uuid16_t manufacturerNameUuid {.u {.type = BLE_UUID_TYPE_16}, .value = manufacturerNameId};
|
||||
|
||||
static constexpr ble_uuid16_t manufacturerNameUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = manufacturerNameId
|
||||
};
|
||||
static constexpr ble_uuid16_t modelNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = modelNumberId};
|
||||
|
||||
static constexpr ble_uuid16_t modelNumberUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = modelNumberId
|
||||
};
|
||||
static constexpr ble_uuid16_t serialNumberUuid {.u {.type = BLE_UUID_TYPE_16}, .value = serialNumberId};
|
||||
|
||||
static constexpr ble_uuid16_t serialNumberUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = serialNumberId
|
||||
};
|
||||
static constexpr ble_uuid16_t fwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = fwRevisionId};
|
||||
|
||||
static constexpr ble_uuid16_t fwRevisionUuid {
|
||||
.u { .type = BLE_UUID_TYPE_16 },
|
||||
.value = fwRevisionId
|
||||
};
|
||||
|
||||
static constexpr ble_uuid16_t hwRevisionUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = hwRevisionId
|
||||
};
|
||||
|
||||
static constexpr ble_uuid16_t swRevisionUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = swRevisionId
|
||||
};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[7];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
static constexpr ble_uuid16_t hwRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = hwRevisionId};
|
||||
|
||||
static constexpr ble_uuid16_t swRevisionUuid {.u {.type = BLE_UUID_TYPE_16}, .value = swRevisionId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[7];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
};
|
||||
}
|
||||
}
|
@ -11,67 +11,60 @@ constexpr ble_uuid128_t DfuService::controlPointCharacteristicUuid;
|
||||
constexpr ble_uuid128_t DfuService::revisionCharacteristicUuid;
|
||||
constexpr ble_uuid128_t DfuService::packetCharacteristicUuid;
|
||||
|
||||
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto dfuService = static_cast<DfuService *>(arg);
|
||||
int DfuServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto dfuService = static_cast<DfuService*>(arg);
|
||||
return dfuService->OnServiceData(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
void NotificationTimerCallback(TimerHandle_t xTimer) {
|
||||
auto notificationManager = static_cast<DfuService::NotificationManager *>(pvTimerGetTimerID(xTimer));
|
||||
auto notificationManager = static_cast<DfuService::NotificationManager*>(pvTimerGetTimerID(xTimer));
|
||||
notificationManager->OnNotificationTimer();
|
||||
}
|
||||
|
||||
void TimeoutTimerCallback(TimerHandle_t xTimer) {
|
||||
auto dfuService = static_cast<DfuService *>(pvTimerGetTimerID(xTimer));
|
||||
auto dfuService = static_cast<DfuService*>(pvTimerGetTimerID(xTimer));
|
||||
dfuService->OnTimeout();
|
||||
}
|
||||
|
||||
DfuService::DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
|
||||
Pinetime::Drivers::SpiNorFlash &spiNorFlash) :
|
||||
systemTask{systemTask},
|
||||
bleController{bleController},
|
||||
dfuImage{spiNorFlash},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &packetCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = nullptr,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &controlPointCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = nullptr,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &revisionCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &revision,
|
||||
DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash)
|
||||
: systemTask {systemTask},
|
||||
bleController {bleController},
|
||||
dfuImage {spiNorFlash},
|
||||
characteristicDefinition {{
|
||||
.uuid = (ble_uuid_t*) &packetCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = nullptr,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = nullptr,
|
||||
},
|
||||
{
|
||||
.uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
|
||||
.access_cb = DfuServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &revision,
|
||||
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
{0}
|
||||
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &serviceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
} {
|
||||
timeoutTimer = xTimerCreate ("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
|
||||
},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &serviceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
timeoutTimer = xTimerCreate("notificationTimer", 10000, pdFALSE, this, TimeoutTimerCallback);
|
||||
}
|
||||
|
||||
void DfuService::Init() {
|
||||
@ -83,55 +76,54 @@ void DfuService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
||||
if(bleController.IsFirmwareUpdating()){
|
||||
int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (bleController.IsFirmwareUpdating()) {
|
||||
xTimerStart(timeoutTimer, 0);
|
||||
}
|
||||
|
||||
|
||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &packetCharacteristicUuid, nullptr,
|
||||
&packetCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &controlPointCharacteristicUuid, nullptr,
|
||||
&controlPointCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t *) &serviceUuid, (ble_uuid_t *) &revisionCharacteristicUuid, nullptr,
|
||||
&revisionCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
|
||||
ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
|
||||
|
||||
if (attributeHandle == packetCharacteristicHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
return WritePacketHandler(connectionHandle, context->om);
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
} else if (attributeHandle == controlPointCharacteristicHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
return ControlPointHandler(connectionHandle, context->om);
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
} else if (attributeHandle == revisionCharacteristicHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
return SendDfuRevision(context->om);
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
NRF_LOG_INFO("[DFU] Unknown Characteristic : %d", attributeHandle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int DfuService::SendDfuRevision(os_mbuf *om) const {
|
||||
int DfuService::SendDfuRevision(os_mbuf* om) const {
|
||||
int res = os_mbuf_append(om, &revision, sizeof(revision));
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
switch (state) {
|
||||
case States::Start: {
|
||||
softdeviceSize = om->om_data[0] + (om->om_data[1] << 8) + (om->om_data[2] << 16) + (om->om_data[3] << 24);
|
||||
bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
|
||||
bleController.FirmwareUpdateTotalBytes(applicationSize);
|
||||
NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize,
|
||||
bootloaderSize, applicationSize);
|
||||
NRF_LOG_INFO(
|
||||
"[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
|
||||
|
||||
dfuImage.Erase();
|
||||
|
||||
uint8_t data[]{16, 1, 1};
|
||||
uint8_t data[] {16, 1, 1};
|
||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
state = States::Init;
|
||||
}
|
||||
@ -139,19 +131,22 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
case States::Init: {
|
||||
uint16_t deviceType = om->om_data[0] + (om->om_data[1] << 8);
|
||||
uint16_t deviceRevision = om->om_data[2] + (om->om_data[3] << 8);
|
||||
uint32_t applicationVersion =
|
||||
om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
uint32_t applicationVersion = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
uint16_t softdeviceArrayLength = om->om_data[8] + (om->om_data[9] << 8);
|
||||
uint16_t sd[softdeviceArrayLength];
|
||||
for (int i = 0; i < softdeviceArrayLength; i++) {
|
||||
sd[i] = om->om_data[10 + (i * 2)] + (om->om_data[10 + (i * 2) + 1] << 8);
|
||||
}
|
||||
expectedCrc =
|
||||
om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
|
||||
expectedCrc = om->om_data[10 + (softdeviceArrayLength * 2)] + (om->om_data[10 + (softdeviceArrayLength * 2) + 1] << 8);
|
||||
|
||||
NRF_LOG_INFO(
|
||||
"[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u",
|
||||
deviceType, deviceRevision, applicationVersion, softdeviceArrayLength, sd[0], expectedCrc);
|
||||
"[DFU] -> Init data received : deviceType = %d, deviceRevision = %d, applicationVersion = %d, nb SD = %d, First SD = %d, CRC = %u",
|
||||
deviceType,
|
||||
deviceRevision,
|
||||
applicationVersion,
|
||||
softdeviceArrayLength,
|
||||
sd[0],
|
||||
expectedCrc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -163,16 +158,18 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
bleController.FirmwareUpdateCurrentBytes(bytesReceived);
|
||||
|
||||
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
|
||||
uint8_t data[5]{static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
||||
(uint8_t) (bytesReceived & 0x000000FFu), (uint8_t) (bytesReceived >> 8u),
|
||||
(uint8_t) (bytesReceived >> 16u), (uint8_t) (bytesReceived >> 24u)};
|
||||
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
||||
(uint8_t) (bytesReceived & 0x000000FFu),
|
||||
(uint8_t) (bytesReceived >> 8u),
|
||||
(uint8_t) (bytesReceived >> 16u),
|
||||
(uint8_t) (bytesReceived >> 24u)};
|
||||
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
|
||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
|
||||
}
|
||||
if (dfuImage.IsComplete()) {
|
||||
uint8_t data[3]{static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ReceiveFirmwareImage),
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||
NRF_LOG_INFO("[DFU] -> Send packet notification : all bytes received!");
|
||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
state = States::Validate;
|
||||
@ -186,7 +183,7 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
auto opcode = static_cast<Opcodes>(om->om_data[0]);
|
||||
NRF_LOG_INFO("[DFU] -> ControlPointHandler");
|
||||
|
||||
@ -214,8 +211,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Opcodes::InitDFUParameters: {
|
||||
if (state != States::Init) {
|
||||
NRF_LOG_INFO("[DFU] -> Init DFU requested, but we are not in Init state");
|
||||
@ -225,11 +221,9 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
NRF_LOG_INFO("[DFU] -> Init DFU parameters %s", isInitComplete ? " complete" : " not complete");
|
||||
|
||||
if (isInitComplete) {
|
||||
uint8_t data[3] {
|
||||
static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::InitDFUParameters),
|
||||
(isInitComplete ? uint8_t{1} : uint8_t{0})
|
||||
};
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::InitDFUParameters),
|
||||
(isInitComplete ? uint8_t {1} : uint8_t {0})};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
return 0;
|
||||
}
|
||||
@ -257,26 +251,22 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf *om) {
|
||||
|
||||
NRF_LOG_INFO("[DFU] -> Validate firmware image requested -- %d", connectionHandle);
|
||||
|
||||
if(dfuImage.Validate()){
|
||||
if (dfuImage.Validate()) {
|
||||
state = States::Validated;
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
|
||||
NRF_LOG_INFO("Image OK");
|
||||
|
||||
uint8_t data[3] {
|
||||
static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)
|
||||
};
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
} else {
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||
NRF_LOG_INFO("Image Error : bad CRC");
|
||||
|
||||
uint8_t data[3] {
|
||||
static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::CrcError)
|
||||
};
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::CrcError)};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
}
|
||||
|
||||
@ -318,11 +308,11 @@ void DfuService::Reset() {
|
||||
}
|
||||
|
||||
DfuService::NotificationManager::NotificationManager() {
|
||||
timer = xTimerCreate ("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
|
||||
timer = xTimerCreate("notificationTimer", 1000, pdFALSE, this, NotificationTimerCallback);
|
||||
}
|
||||
|
||||
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t s) {
|
||||
if(size != 0 || s > 10)
|
||||
bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t s) {
|
||||
if (size != 0 || s > 10)
|
||||
return false;
|
||||
|
||||
connectionHandle = connection;
|
||||
@ -334,14 +324,14 @@ bool DfuService::NotificationManager::AsyncSend(uint16_t connection, uint16_t ch
|
||||
}
|
||||
|
||||
void DfuService::NotificationManager::OnNotificationTimer() {
|
||||
if(size > 0) {
|
||||
if (size > 0) {
|
||||
Send(connectionHandle, characteristicHandle, buffer, size);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t *data, const size_t s) {
|
||||
auto *om = ble_hs_mbuf_from_flat(data, s);
|
||||
void DfuService::NotificationManager::Send(uint16_t connection, uint16_t charactHandle, const uint8_t* data, const size_t s) {
|
||||
auto* om = ble_hs_mbuf_from_flat(data, s);
|
||||
auto ret = ble_gattc_notify_custom(connection, charactHandle, om);
|
||||
ASSERT(ret == 0);
|
||||
}
|
||||
@ -354,27 +344,29 @@ void DfuService::NotificationManager::Reset() {
|
||||
}
|
||||
|
||||
void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc) {
|
||||
if(chunkSize != 20) return;
|
||||
if (chunkSize != 20)
|
||||
return;
|
||||
this->chunkSize = chunkSize;
|
||||
this->totalSize = totalSize;
|
||||
this->expectedCrc = expectedCrc;
|
||||
this->ready = true;
|
||||
}
|
||||
|
||||
void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
|
||||
if(!ready) return;
|
||||
void DfuService::DfuImage::Append(uint8_t* data, size_t size) {
|
||||
if (!ready)
|
||||
return;
|
||||
ASSERT(size <= 20);
|
||||
|
||||
std::memcpy(tempBuffer + bufferWriteIndex, data, size);
|
||||
bufferWriteIndex += size;
|
||||
|
||||
if(bufferWriteIndex == bufferSize) {
|
||||
if (bufferWriteIndex == bufferSize) {
|
||||
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
||||
totalWriteIndex += bufferWriteIndex;
|
||||
bufferWriteIndex = 0;
|
||||
}
|
||||
|
||||
if(bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
|
||||
if (bufferWriteIndex > 0 && totalWriteIndex + bufferWriteIndex == totalSize) {
|
||||
spiNorFlash.Write(writeOffset + totalWriteIndex, tempBuffer, bufferWriteIndex);
|
||||
totalWriteIndex += bufferWriteIndex;
|
||||
if (totalSize < maxSize)
|
||||
@ -383,15 +375,16 @@ void DfuService::DfuImage::Append(uint8_t *data, size_t size) {
|
||||
}
|
||||
|
||||
void DfuService::DfuImage::WriteMagicNumber() {
|
||||
uint32_t magic[4] = { // TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
|
||||
0xf395c277,
|
||||
0x7fefd260,
|
||||
0x0f505235,
|
||||
0x8079b62c,
|
||||
uint32_t magic[4] = {
|
||||
// TODO When this variable is a static constexpr, the values written to the memory are not correct. Why?
|
||||
0xf395c277,
|
||||
0x7fefd260,
|
||||
0x0f505235,
|
||||
0x8079b62c,
|
||||
};
|
||||
|
||||
uint32_t offset = writeOffset + (maxSize - (4 * sizeof(uint32_t)));
|
||||
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t *>(magic), 4 * sizeof(uint32_t));
|
||||
spiNorFlash.Write(offset, reinterpret_cast<const uint8_t*>(magic), 4 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void DfuService::DfuImage::Erase() {
|
||||
@ -421,7 +414,7 @@ bool DfuService::DfuImage::Validate() {
|
||||
return (crc == expectedCrc);
|
||||
}
|
||||
|
||||
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc) {
|
||||
uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc) {
|
||||
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
@ -436,6 +429,7 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const *p_data, uint32_t size,
|
||||
}
|
||||
|
||||
bool DfuService::DfuImage::IsComplete() {
|
||||
if(!ready) return false;
|
||||
if (!ready)
|
||||
return false;
|
||||
return totalWriteIndex == totalSize;
|
||||
}
|
||||
|
@ -20,146 +20,139 @@ namespace Pinetime {
|
||||
class Ble;
|
||||
|
||||
class DfuService {
|
||||
public:
|
||||
DfuService(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||
void Init();
|
||||
int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
void OnTimeout();
|
||||
void Reset();
|
||||
|
||||
class NotificationManager {
|
||||
public:
|
||||
DfuService(Pinetime::System::SystemTask &systemTask, Pinetime::Controllers::Ble &bleController,
|
||||
Pinetime::Drivers::SpiNorFlash &spiNorFlash);
|
||||
void Init();
|
||||
int OnServiceData(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
void OnTimeout();
|
||||
void Reset();
|
||||
|
||||
class NotificationManager {
|
||||
public:
|
||||
NotificationManager();
|
||||
bool AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t *data, size_t size);
|
||||
void Send(uint16_t connection, uint16_t characteristicHandle, const uint8_t *data, const size_t s);
|
||||
private:
|
||||
TimerHandle_t timer;
|
||||
uint16_t connectionHandle = 0;
|
||||
uint16_t characteristicHandle = 0;
|
||||
size_t size = 0;
|
||||
uint8_t buffer[10];
|
||||
public:
|
||||
void OnNotificationTimer();
|
||||
void Reset();
|
||||
};
|
||||
class DfuImage {
|
||||
public:
|
||||
DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash{spiNorFlash} {}
|
||||
void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc);
|
||||
void Erase();
|
||||
void Append(uint8_t* data, size_t size);
|
||||
bool Validate();
|
||||
bool IsComplete();
|
||||
|
||||
private:
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
static constexpr size_t bufferSize = 200;
|
||||
bool ready = false;
|
||||
size_t chunkSize = 0;
|
||||
size_t totalSize = 0;
|
||||
size_t maxSize = 475136;
|
||||
size_t bufferWriteIndex = 0;
|
||||
size_t totalWriteIndex = 0;
|
||||
static constexpr size_t writeOffset = 0x40000;
|
||||
uint8_t tempBuffer[bufferSize];
|
||||
uint16_t expectedCrc = 0;
|
||||
|
||||
void WriteMagicNumber();
|
||||
uint16_t ComputeCrc(uint8_t const *p_data, uint32_t size, uint16_t const *p_crc);
|
||||
|
||||
};
|
||||
NotificationManager();
|
||||
bool AsyncSend(uint16_t connection, uint16_t charactHandle, uint8_t* data, size_t size);
|
||||
void Send(uint16_t connection, uint16_t characteristicHandle, const uint8_t* data, const size_t s);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
Pinetime::Controllers::Ble &bleController;
|
||||
DfuImage dfuImage;
|
||||
NotificationManager notificationManager;
|
||||
TimerHandle_t timer;
|
||||
uint16_t connectionHandle = 0;
|
||||
uint16_t characteristicHandle = 0;
|
||||
size_t size = 0;
|
||||
uint8_t buffer[10];
|
||||
|
||||
static constexpr uint16_t dfuServiceId{0x1530};
|
||||
static constexpr uint16_t packetCharacteristicId{0x1532};
|
||||
static constexpr uint16_t controlPointCharacteristicId{0x1531};
|
||||
static constexpr uint16_t revisionCharacteristicId{0x1534};
|
||||
public:
|
||||
void OnNotificationTimer();
|
||||
void Reset();
|
||||
};
|
||||
class DfuImage {
|
||||
public:
|
||||
DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
|
||||
}
|
||||
void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc);
|
||||
void Erase();
|
||||
void Append(uint8_t* data, size_t size);
|
||||
bool Validate();
|
||||
bool IsComplete();
|
||||
|
||||
uint16_t revision{0x0008};
|
||||
|
||||
static constexpr ble_uuid128_t serviceUuid{
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static constexpr ble_uuid128_t packetCharacteristicUuid{
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static constexpr ble_uuid128_t controlPointCharacteristicUuid{
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static constexpr ble_uuid128_t revisionCharacteristicUuid{
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}
|
||||
};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[4];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
uint16_t packetCharacteristicHandle;
|
||||
uint16_t controlPointCharacteristicHandle;
|
||||
uint16_t revisionCharacteristicHandle;
|
||||
|
||||
enum class States : uint8_t {
|
||||
Idle, Init, Start, Data, Validate, Validated
|
||||
};
|
||||
States state = States::Idle;
|
||||
|
||||
enum class ImageTypes : uint8_t {
|
||||
NoImage = 0x00,
|
||||
SoftDevice = 0x01,
|
||||
Bootloader = 0x02,
|
||||
SoftDeviceAndBootloader = 0x03,
|
||||
Application = 0x04
|
||||
};
|
||||
|
||||
enum class Opcodes : uint8_t {
|
||||
StartDFU = 0x01,
|
||||
InitDFUParameters = 0x02,
|
||||
ReceiveFirmwareImage = 0x03,
|
||||
ValidateFirmware = 0x04,
|
||||
ActivateImageAndReset = 0x05,
|
||||
PacketReceiptNotificationRequest = 0x08,
|
||||
Response = 0x10,
|
||||
PacketReceiptNotification = 0x11
|
||||
};
|
||||
|
||||
enum class ErrorCodes {
|
||||
NoError = 0x01,
|
||||
InvalidState = 0x02,
|
||||
NotSupported = 0x03,
|
||||
DataSizeExceedsLimits = 0x04,
|
||||
CrcError = 0x05,
|
||||
OperationFailed = 0x06
|
||||
};
|
||||
|
||||
uint8_t nbPacketsToNotify = 0;
|
||||
uint32_t nbPacketReceived = 0;
|
||||
uint32_t bytesReceived = 0;
|
||||
|
||||
uint32_t softdeviceSize = 0;
|
||||
uint32_t bootloaderSize = 0;
|
||||
uint32_t applicationSize = 0;
|
||||
private:
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
static constexpr size_t bufferSize = 200;
|
||||
bool ready = false;
|
||||
size_t chunkSize = 0;
|
||||
size_t totalSize = 0;
|
||||
size_t maxSize = 475136;
|
||||
size_t bufferWriteIndex = 0;
|
||||
size_t totalWriteIndex = 0;
|
||||
static constexpr size_t writeOffset = 0x40000;
|
||||
uint8_t tempBuffer[bufferSize];
|
||||
uint16_t expectedCrc = 0;
|
||||
|
||||
int SendDfuRevision(os_mbuf *om) const;
|
||||
int WritePacketHandler(uint16_t connectionHandle, os_mbuf *om);
|
||||
int ControlPointHandler(uint16_t connectionHandle, os_mbuf *om);
|
||||
void WriteMagicNumber();
|
||||
uint16_t ComputeCrc(uint8_t const* p_data, uint32_t size, uint16_t const* p_crc);
|
||||
};
|
||||
|
||||
TimerHandle_t timeoutTimer;
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
DfuImage dfuImage;
|
||||
NotificationManager notificationManager;
|
||||
|
||||
static constexpr uint16_t dfuServiceId {0x1530};
|
||||
static constexpr uint16_t packetCharacteristicId {0x1532};
|
||||
static constexpr uint16_t controlPointCharacteristicId {0x1531};
|
||||
static constexpr uint16_t revisionCharacteristicId {0x1534};
|
||||
|
||||
uint16_t revision {0x0008};
|
||||
|
||||
static constexpr ble_uuid128_t serviceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
|
||||
|
||||
static constexpr ble_uuid128_t packetCharacteristicUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00}};
|
||||
|
||||
static constexpr ble_uuid128_t controlPointCharacteristicUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00}};
|
||||
|
||||
static constexpr ble_uuid128_t revisionCharacteristicUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00}};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[4];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
uint16_t packetCharacteristicHandle;
|
||||
uint16_t controlPointCharacteristicHandle;
|
||||
uint16_t revisionCharacteristicHandle;
|
||||
|
||||
enum class States : uint8_t { Idle, Init, Start, Data, Validate, Validated };
|
||||
States state = States::Idle;
|
||||
|
||||
enum class ImageTypes : uint8_t {
|
||||
NoImage = 0x00,
|
||||
SoftDevice = 0x01,
|
||||
Bootloader = 0x02,
|
||||
SoftDeviceAndBootloader = 0x03,
|
||||
Application = 0x04
|
||||
};
|
||||
|
||||
enum class Opcodes : uint8_t {
|
||||
StartDFU = 0x01,
|
||||
InitDFUParameters = 0x02,
|
||||
ReceiveFirmwareImage = 0x03,
|
||||
ValidateFirmware = 0x04,
|
||||
ActivateImageAndReset = 0x05,
|
||||
PacketReceiptNotificationRequest = 0x08,
|
||||
Response = 0x10,
|
||||
PacketReceiptNotification = 0x11
|
||||
};
|
||||
|
||||
enum class ErrorCodes {
|
||||
NoError = 0x01,
|
||||
InvalidState = 0x02,
|
||||
NotSupported = 0x03,
|
||||
DataSizeExceedsLimits = 0x04,
|
||||
CrcError = 0x05,
|
||||
OperationFailed = 0x06
|
||||
};
|
||||
|
||||
uint8_t nbPacketsToNotify = 0;
|
||||
uint32_t nbPacketReceived = 0;
|
||||
uint32_t bytesReceived = 0;
|
||||
|
||||
uint32_t softdeviceSize = 0;
|
||||
uint32_t bootloaderSize = 0;
|
||||
uint32_t applicationSize = 0;
|
||||
uint16_t expectedCrc = 0;
|
||||
|
||||
int SendDfuRevision(os_mbuf* om) const;
|
||||
int WritePacketHandler(uint16_t connectionHandle, os_mbuf* om);
|
||||
int ControlPointHandler(uint16_t connectionHandle, os_mbuf* om);
|
||||
|
||||
TimerHandle_t timeoutTimer;
|
||||
};
|
||||
}
|
||||
}
|
@ -8,39 +8,29 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
|
||||
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
|
||||
|
||||
namespace {
|
||||
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* heartRateService = static_cast<HeartRateService*>(arg);
|
||||
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Refactoring - remove dependency to SystemTask
|
||||
HeartRateService::HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController) :
|
||||
system{system},
|
||||
heartRateController{heartRateController},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &heartRateMeasurementUuid,
|
||||
.access_cb = HeartRateServiceServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &heartRateMeasurementHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &heartRateServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
|
||||
: system {system},
|
||||
heartRateController {heartRateController},
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
|
||||
.access_cb = HeartRateServiceServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &heartRateMeasurementHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &heartRateServiceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
// TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service)
|
||||
heartRateController.SetService(this);
|
||||
}
|
||||
@ -54,9 +44,8 @@ void HeartRateService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == heartRateMeasurementHandle) {
|
||||
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == heartRateMeasurementHandle) {
|
||||
NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle);
|
||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||
|
||||
@ -68,7 +57,7 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
|
||||
|
||||
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
|
||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||
auto *om = ble_hs_mbuf_from_flat(buffer, 2);
|
||||
auto* om = ble_hs_mbuf_from_flat(buffer, 2);
|
||||
|
||||
uint16_t connectionHandle = system.nimble().connHandle();
|
||||
|
||||
|
@ -12,33 +12,26 @@ namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class HeartRateController;
|
||||
class HeartRateService {
|
||||
public:
|
||||
HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController);
|
||||
void Init();
|
||||
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
void OnNewHeartRateValue(uint8_t hearRateValue);
|
||||
public:
|
||||
HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController);
|
||||
void Init();
|
||||
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
void OnNewHeartRateValue(uint8_t hearRateValue);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask &system;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
static constexpr uint16_t heartRateServiceId {0x180D};
|
||||
static constexpr uint16_t heartRateMeasurementId {0x2A37};
|
||||
Pinetime::System::SystemTask& system;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
static constexpr uint16_t heartRateServiceId {0x180D};
|
||||
static constexpr uint16_t heartRateMeasurementId {0x2A37};
|
||||
|
||||
static constexpr ble_uuid16_t heartRateServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = heartRateServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t heartRateServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateServiceId};
|
||||
|
||||
static constexpr ble_uuid16_t heartRateMeasurementUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = heartRateMeasurementId
|
||||
};
|
||||
static constexpr ble_uuid16_t heartRateMeasurementUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateMeasurementId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t heartRateMeasurementHandle;
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t heartRateMeasurementHandle;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,49 +9,42 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid;
|
||||
constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid;
|
||||
|
||||
namespace {
|
||||
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto *immediateAlertService = static_cast<ImmediateAlertService *>(arg);
|
||||
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg);
|
||||
return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
const char* ToString(ImmediateAlertService::Levels level) {
|
||||
switch (level) {
|
||||
case ImmediateAlertService::Levels::NoAlert: return "Alert : None";
|
||||
case ImmediateAlertService::Levels::HighAlert: return "Alert : High";
|
||||
case ImmediateAlertService::Levels::MildAlert: return "Alert : Mild";
|
||||
default: return "";
|
||||
case ImmediateAlertService::Levels::NoAlert:
|
||||
return "Alert : None";
|
||||
case ImmediateAlertService::Levels::HighAlert:
|
||||
return "Alert : High";
|
||||
case ImmediateAlertService::Levels::MildAlert:
|
||||
return "Alert : Mild";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
||||
systemTask{systemTask},
|
||||
notificationManager{notificationManager},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &alertLevelUuid,
|
||||
.access_cb = AlertLevelCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = &alertLevelHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &immediateAlertServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
|
||||
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager)
|
||||
: systemTask {systemTask},
|
||||
notificationManager {notificationManager},
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid,
|
||||
.access_cb = AlertLevelCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = &alertLevelHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &immediateAlertServiceUuid,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
void ImmediateAlertService::Init() {
|
||||
@ -63,9 +56,9 @@ void ImmediateAlertService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == alertLevelHandle) {
|
||||
if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == alertLevelHandle) {
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
|
||||
auto* alertString = ToString(alertLevel);
|
||||
|
||||
|
@ -12,39 +12,28 @@ namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class NotificationManager;
|
||||
class ImmediateAlertService {
|
||||
public:
|
||||
enum class Levels : uint8_t {
|
||||
NoAlert = 0,
|
||||
MildAlert = 1,
|
||||
HighAlert = 2
|
||||
};
|
||||
public:
|
||||
enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 };
|
||||
|
||||
ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
void Init();
|
||||
int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager);
|
||||
void Init();
|
||||
int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
NotificationManager& notificationManager;
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
NotificationManager& notificationManager;
|
||||
|
||||
static constexpr uint16_t immediateAlertServiceId {0x1802};
|
||||
static constexpr uint16_t alertLevelId {0x2A06};
|
||||
static constexpr uint16_t immediateAlertServiceId {0x1802};
|
||||
static constexpr uint16_t alertLevelId {0x2A06};
|
||||
|
||||
static constexpr ble_uuid16_t immediateAlertServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = immediateAlertServiceId
|
||||
};
|
||||
static constexpr ble_uuid16_t immediateAlertServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = immediateAlertServiceId};
|
||||
|
||||
static constexpr ble_uuid16_t alertLevelUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = alertLevelId
|
||||
};
|
||||
static constexpr ble_uuid16_t alertLevelUuid {.u {.type = BLE_UUID_TYPE_16}, .value = alertLevelId};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t alertLevelHandle;
|
||||
uint16_t alertLevelHandle;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,12 @@
|
||||
#include "MusicService.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto musicService = static_cast<Pinetime::Controllers::MusicService *>(arg);
|
||||
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto musicService = static_cast<Pinetime::Controllers::MusicService*>(arg);
|
||||
return musicService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &system) : m_system(system) {
|
||||
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||
msUuid.value[14] = msId[0];
|
||||
msUuid.value[15] = msId[1];
|
||||
|
||||
@ -86,82 +86,51 @@ Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &
|
||||
msShuffleCharUuid.value[13] = msShuffleCharId[1];
|
||||
msShuffleCharUuid.value[14] = msId[0];
|
||||
msShuffleCharUuid.value[15] = msId[1];
|
||||
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&msEventCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle
|
||||
};
|
||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&msStatusCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&msTrackCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&msArtistCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[4] = {.uuid = (ble_uuid_t *) (&msAlbumCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[5] = {.uuid = (ble_uuid_t *) (&msPositionCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[6] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[7] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[8] = {.uuid = (ble_uuid_t *) (&msTrackNumberCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[9] = {.uuid = (ble_uuid_t *) (&msTrackTotalCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[10] = {.uuid = (ble_uuid_t *) (&msPlaybackSpeedCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[11] = {.uuid = (ble_uuid_t *) (&msRepeatCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[12] = {.uuid = (ble_uuid_t *) (&msShuffleCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t*) (&msEventCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle};
|
||||
characteristicDefinition[1] = {
|
||||
.uuid = (ble_uuid_t*) (&msStatusCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[2] = {
|
||||
.uuid = (ble_uuid_t*) (&msTrackCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[3] = {
|
||||
.uuid = (ble_uuid_t*) (&msArtistCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[4] = {
|
||||
.uuid = (ble_uuid_t*) (&msAlbumCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[5] = {
|
||||
.uuid = (ble_uuid_t*) (&msPositionCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[6] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[7] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[8] = {.uuid = (ble_uuid_t*) (&msTrackNumberCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[9] = {.uuid = (ble_uuid_t*) (&msTrackTotalCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[10] = {.uuid = (ble_uuid_t*) (&msPlaybackSpeedCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[11] = {
|
||||
.uuid = (ble_uuid_t*) (&msRepeatCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[12] = {
|
||||
.uuid = (ble_uuid_t*) (&msShuffleCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[13] = {0};
|
||||
|
||||
serviceDefinition[0] = {
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &msUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
};
|
||||
|
||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &msUuid, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[1] = {0};
|
||||
|
||||
|
||||
artistName = "Waiting for";
|
||||
albumName = "";
|
||||
trackName = "track information..";
|
||||
@ -177,41 +146,40 @@ void Pinetime::Controllers::MusicService::Init() {
|
||||
int res = 0;
|
||||
res = ble_gatts_count_cfg(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
|
||||
res = ble_gatts_add_svcs(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
|
||||
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t data[notifSize + 1];
|
||||
data[notifSize] = '\0';
|
||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||
char *s = (char *) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msArtistCharUuid) == 0) {
|
||||
char* s = (char*) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msArtistCharUuid) == 0) {
|
||||
artistName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackCharUuid) == 0) {
|
||||
trackName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msAlbumCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msAlbumCharUuid) == 0) {
|
||||
albumName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msStatusCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msStatusCharUuid) == 0) {
|
||||
playing = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msRepeatCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msRepeatCharUuid) == 0) {
|
||||
repeat = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msShuffleCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msShuffleCharUuid) == 0) {
|
||||
shuffle = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPositionCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPositionCharUuid) == 0) {
|
||||
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTotalLengthCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTotalLengthCharUuid) == 0) {
|
||||
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackNumberCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackNumberCharUuid) == 0) {
|
||||
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackTotalCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackTotalCharUuid) == 0) {
|
||||
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPlaybackSpeedCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPlaybackSpeedCharUuid) == 0) {
|
||||
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
|
||||
}
|
||||
}
|
||||
@ -239,14 +207,14 @@ float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
|
||||
}
|
||||
|
||||
void Pinetime::Controllers::MusicService::event(char event) {
|
||||
auto *om = ble_hs_mbuf_from_flat(&event, 1);
|
||||
|
||||
auto* om = ble_hs_mbuf_from_flat(&event, 1);
|
||||
|
||||
uint16_t connectionHandle = m_system.nimble().connHandle();
|
||||
|
||||
|
||||
if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ble_gattc_notify_custom(connectionHandle, eventHandle, om);
|
||||
}
|
||||
|
||||
@ -257,4 +225,3 @@ int Pinetime::Controllers::MusicService::getProgress() {
|
||||
int Pinetime::Controllers::MusicService::getTrackLength() {
|
||||
return trackLength;
|
||||
}
|
||||
|
||||
|
@ -26,40 +26,40 @@
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
//00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define MUSIC_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00}
|
||||
// 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define MUSIC_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
|
||||
|
||||
class MusicService {
|
||||
public:
|
||||
explicit MusicService(Pinetime::System::SystemTask &system);
|
||||
|
||||
explicit MusicService(Pinetime::System::SystemTask& system);
|
||||
|
||||
void Init();
|
||||
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
|
||||
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
void event(char event);
|
||||
|
||||
|
||||
std::string getArtist();
|
||||
|
||||
|
||||
std::string getTrack();
|
||||
|
||||
|
||||
std::string getAlbum();
|
||||
|
||||
|
||||
int getProgress();
|
||||
|
||||
|
||||
int getTrackLength();
|
||||
|
||||
|
||||
float getPlaybackSpeed();
|
||||
|
||||
|
||||
bool isPlaying();
|
||||
|
||||
|
||||
static const char EVENT_MUSIC_OPEN = 0xe0;
|
||||
static const char EVENT_MUSIC_PLAY = 0x00;
|
||||
static const char EVENT_MUSIC_PAUSE = 0x01;
|
||||
@ -67,11 +67,9 @@ namespace Pinetime {
|
||||
static const char EVENT_MUSIC_PREV = 0x04;
|
||||
static const char EVENT_MUSIC_VOLUP = 0x05;
|
||||
static const char EVENT_MUSIC_VOLDOWN = 0x06;
|
||||
|
||||
enum MusicStatus {
|
||||
NotPlaying = 0x00,
|
||||
Playing = 0x01
|
||||
};
|
||||
|
||||
enum MusicStatus { NotPlaying = 0x00, Playing = 0x01 };
|
||||
|
||||
private:
|
||||
static constexpr uint8_t msId[2] = {0x00, 0x00};
|
||||
static constexpr uint8_t msEventCharId[2] = {0x01, 0x00};
|
||||
@ -86,84 +84,44 @@ namespace Pinetime {
|
||||
static constexpr uint8_t msPlaybackSpeedCharId[2] = {0x0a, 0x00};
|
||||
static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00};
|
||||
static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00};
|
||||
|
||||
ble_uuid128_t msUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
|
||||
ble_uuid128_t msEventCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msStatusCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msArtistCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTrackCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msAlbumCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msPositionCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTotalLengthCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTrackNumberCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msTrackTotalCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msPlaybackSpeedCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msRepeatCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t msShuffleCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = MUSIC_SERVICE_UUID_BASE
|
||||
};
|
||||
|
||||
|
||||
ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
|
||||
ble_uuid128_t msEventCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msStatusCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msArtistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msAlbumCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msPositionCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTotalLengthCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackNumberCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackTotalCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msPlaybackSpeedCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msRepeatCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msShuffleCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[14];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
|
||||
uint16_t eventHandle;
|
||||
|
||||
|
||||
std::string artistName;
|
||||
std::string albumName;
|
||||
std::string trackName;
|
||||
|
||||
|
||||
bool playing;
|
||||
|
||||
|
||||
int trackProgress;
|
||||
int trackLength;
|
||||
int trackNumber;
|
||||
int tracksTotal;
|
||||
|
||||
|
||||
float playbackSpeed;
|
||||
|
||||
|
||||
bool repeat;
|
||||
bool shuffle;
|
||||
|
||||
Pinetime::System::SystemTask &m_system;
|
||||
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,12 +20,12 @@
|
||||
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto navService = static_cast<Pinetime::Controllers::NavigationService *>(arg);
|
||||
int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
|
||||
return navService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask &system) : m_system(system) {
|
||||
Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||
navUuid.value[14] = navId[0];
|
||||
navUuid.value[15] = navId[1];
|
||||
|
||||
@ -49,35 +49,25 @@ Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::Sy
|
||||
navProgressCharUuid.value[14] = navId[0];
|
||||
navProgressCharUuid.value[15] = navId[1];
|
||||
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&navFlagCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[0] = {
|
||||
.uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
|
||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&navNarrativeCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&navManDistCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&navProgressCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
|
||||
};
|
||||
characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid),
|
||||
.access_cb = NAVCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
|
||||
characteristicDefinition[4] = {0};
|
||||
|
||||
serviceDefinition[0] = {
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &navUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
};
|
||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[1] = {0};
|
||||
|
||||
m_progress = 0;
|
||||
@ -92,45 +82,39 @@ void Pinetime::Controllers::NavigationService::Init() {
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t data[notifSize + 1];
|
||||
data[notifSize] = '\0';
|
||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||
char *s = (char *) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navFlagCharUuid) == 0) {
|
||||
char* s = (char*) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) {
|
||||
m_flag = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navNarrativeCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) {
|
||||
m_narrative = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navManDistCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) {
|
||||
m_manDist = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &navProgressCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) {
|
||||
m_progress = data[0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::NavigationService::getFlag()
|
||||
{
|
||||
return m_flag;
|
||||
std::string Pinetime::Controllers::NavigationService::getFlag() {
|
||||
return m_flag;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::NavigationService::getNarrative()
|
||||
{
|
||||
return m_narrative;
|
||||
std::string Pinetime::Controllers::NavigationService::getNarrative() {
|
||||
return m_narrative;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::NavigationService::getManDist()
|
||||
{
|
||||
return m_manDist;
|
||||
std::string Pinetime::Controllers::NavigationService::getManDist() {
|
||||
return m_manDist;
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::NavigationService::getProgress()
|
||||
{
|
||||
return m_progress;
|
||||
int Pinetime::Controllers::NavigationService::getProgress() {
|
||||
return m_progress;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,9 @@
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
//c7e60000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NAVIGATION_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00}
|
||||
// c7e60000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define NAVIGATION_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
@ -37,12 +38,11 @@ namespace Pinetime {
|
||||
|
||||
class NavigationService {
|
||||
public:
|
||||
explicit NavigationService(Pinetime::System::SystemTask &system);
|
||||
explicit NavigationService(Pinetime::System::SystemTask& system);
|
||||
|
||||
void Init();
|
||||
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt);
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
std::string getFlag();
|
||||
|
||||
@ -59,27 +59,12 @@ namespace Pinetime {
|
||||
static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
|
||||
static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
|
||||
|
||||
ble_uuid128_t navUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
|
||||
ble_uuid128_t navFlagCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navNarrativeCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navManDistCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navProgressCharUuid{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = NAVIGATION_SERVICE_UUID_BASE
|
||||
};
|
||||
ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t navManDistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t navProgressCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[5];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
@ -89,8 +74,7 @@ namespace Pinetime {
|
||||
std::string m_manDist;
|
||||
int m_progress;
|
||||
|
||||
Pinetime::System::SystemTask &m_system;
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,36 +19,37 @@ using namespace Pinetime::Controllers;
|
||||
|
||||
NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Controllers::HeartRateController& heartRateController) :
|
||||
systemTask{systemTask},
|
||||
bleController{bleController},
|
||||
dateTimeController{dateTimeController},
|
||||
notificationManager{notificationManager},
|
||||
spiNorFlash{spiNorFlash},
|
||||
dfuService{systemTask, bleController, spiNorFlash},
|
||||
currentTimeClient{dateTimeController},
|
||||
anService{systemTask, notificationManager},
|
||||
alertNotificationClient{systemTask, notificationManager},
|
||||
currentTimeService{dateTimeController},
|
||||
musicService{systemTask},
|
||||
navService{systemTask},
|
||||
batteryInformationService{batteryController},
|
||||
immediateAlertService{systemTask, notificationManager},
|
||||
heartRateService{systemTask, heartRateController},
|
||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||
DateTime& dateTimeController,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Controllers::HeartRateController& heartRateController)
|
||||
: systemTask {systemTask},
|
||||
bleController {bleController},
|
||||
dateTimeController {dateTimeController},
|
||||
notificationManager {notificationManager},
|
||||
spiNorFlash {spiNorFlash},
|
||||
dfuService {systemTask, bleController, spiNorFlash},
|
||||
currentTimeClient {dateTimeController},
|
||||
anService {systemTask, notificationManager},
|
||||
alertNotificationClient {systemTask, notificationManager},
|
||||
currentTimeService {dateTimeController},
|
||||
musicService {systemTask},
|
||||
navService {systemTask},
|
||||
batteryInformationService {batteryController},
|
||||
immediateAlertService {systemTask, notificationManager},
|
||||
heartRateService {systemTask, heartRateController},
|
||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||
}
|
||||
|
||||
int GAPEventCallback(struct ble_gap_event *event, void *arg) {
|
||||
int GAPEventCallback(struct ble_gap_event* event, void* arg) {
|
||||
auto nimbleController = static_cast<NimbleController*>(arg);
|
||||
return nimbleController->OnGAPEvent(event);
|
||||
}
|
||||
|
||||
void NimbleController::Init() {
|
||||
while (!ble_hs_synced()) {}
|
||||
while (!ble_hs_synced()) {
|
||||
}
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
@ -81,7 +82,8 @@ void NimbleController::Init() {
|
||||
}
|
||||
|
||||
void NimbleController::StartAdvertising() {
|
||||
if(bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active()) return;
|
||||
if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active())
|
||||
return;
|
||||
|
||||
ble_svc_gap_device_name_set(deviceName);
|
||||
|
||||
@ -101,29 +103,27 @@ void NimbleController::StartAdvertising() {
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
||||
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
||||
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
||||
fields.uuids128 = &dfuServiceUuid;
|
||||
fields.num_uuids128 = 1;
|
||||
fields.uuids128_is_complete = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
rsp_fields.name = (uint8_t *)deviceName;
|
||||
rsp_fields.name = (uint8_t*) deviceName;
|
||||
rsp_fields.name_len = strlen(deviceName);
|
||||
rsp_fields.name_is_complete = 1;
|
||||
|
||||
ble_gap_adv_set_fields(&fields);
|
||||
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
||||
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
||||
|
||||
ble_gap_adv_rsp_set_fields(&rsp_fields);
|
||||
// ASSERT(res == 0);
|
||||
// ASSERT(res == 0);
|
||||
|
||||
ble_gap_adv_start(addrType, NULL, 180000,
|
||||
&adv_params, GAPEventCallback, this);
|
||||
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
||||
ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
|
||||
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
||||
// For now, the advertising is restarted as soon as it ends. There may be a race condition
|
||||
// that prevent the advertising from restarting reliably.
|
||||
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of
|
||||
@ -131,7 +131,7 @@ void NimbleController::StartAdvertising() {
|
||||
// the application has been woken up, for example.
|
||||
}
|
||||
|
||||
int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
|
||||
@ -141,8 +141,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
|
||||
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
NRF_LOG_INFO("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
@ -154,8 +153,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
connectionHandle = event->connect.conn_handle;
|
||||
// Service discovery is deffered via systemtask
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
|
||||
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
|
||||
@ -178,19 +176,16 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d "
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
|
||||
event->subscribe.conn_handle,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.reason,
|
||||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate);
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
|
||||
event->subscribe.conn_handle,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.reason,
|
||||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate);
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.channel_id,
|
||||
event->mtu.value);
|
||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||
@ -216,9 +211,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
|
||||
NRF_LOG_INFO("received %s; conn_handle=%d attr_handle=%d "
|
||||
"attr_len=%d",
|
||||
event->notify_rx.indication ?
|
||||
"indication" :
|
||||
"notification",
|
||||
event->notify_rx.indication ? "indication" : "notification",
|
||||
event->notify_rx.conn_handle,
|
||||
event->notify_rx.attr_handle,
|
||||
notifSize);
|
||||
@ -229,7 +222,7 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
/* Attribute data is contained in event->notify_rx.attr_data. */
|
||||
|
||||
default:
|
||||
// NRF_LOG_INFO("Advertising event : %d", event->type);
|
||||
// NRF_LOG_INFO("Advertising event : %d", event->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -239,8 +232,6 @@ void NimbleController::StartDiscovery() {
|
||||
serviceDiscovery.StartDiscovery(connectionHandle);
|
||||
}
|
||||
|
||||
|
||||
uint16_t NimbleController::connHandle() {
|
||||
return connectionHandle;
|
||||
return connectionHandle;
|
||||
}
|
||||
|
||||
|
@ -36,62 +36,69 @@ namespace Pinetime {
|
||||
|
||||
class NimbleController {
|
||||
|
||||
public:
|
||||
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Controllers::HeartRateController& heartRateController);
|
||||
void Init();
|
||||
void StartAdvertising();
|
||||
int OnGAPEvent(ble_gap_event *event);
|
||||
public:
|
||||
NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
Controllers::HeartRateController& heartRateController);
|
||||
void Init();
|
||||
void StartAdvertising();
|
||||
int OnGAPEvent(ble_gap_event* event);
|
||||
|
||||
int OnDiscoveryEvent(uint16_t i, const ble_gatt_error *pError, const ble_gatt_svc *pSvc);
|
||||
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute);
|
||||
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
||||
int OnDiscoveryEvent(uint16_t i, const ble_gatt_error* pError, const ble_gatt_svc* pSvc);
|
||||
int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
|
||||
int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
|
||||
const ble_gatt_error* error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc* descriptor);
|
||||
|
||||
void StartDiscovery();
|
||||
void StartDiscovery();
|
||||
|
||||
Pinetime::Controllers::MusicService& music() {return musicService;};
|
||||
Pinetime::Controllers::NavigationService& navigation() {return navService;};
|
||||
Pinetime::Controllers::AlertNotificationService& alertService() {return anService;};
|
||||
Pinetime::Controllers::MusicService& music() {
|
||||
return musicService;
|
||||
};
|
||||
Pinetime::Controllers::NavigationService& navigation() {
|
||||
return navService;
|
||||
};
|
||||
Pinetime::Controllers::AlertNotificationService& alertService() {
|
||||
return anService;
|
||||
};
|
||||
|
||||
uint16_t connHandle();
|
||||
uint16_t connHandle();
|
||||
|
||||
private:
|
||||
static constexpr const char* deviceName = "InfiniTime";
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
DateTime& dateTimeController;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
Pinetime::Controllers::DfuService dfuService;
|
||||
private:
|
||||
static constexpr const char* deviceName = "InfiniTime";
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
DateTime& dateTimeController;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
Pinetime::Controllers::DfuService dfuService;
|
||||
|
||||
DeviceInformationService deviceInformationService;
|
||||
CurrentTimeClient currentTimeClient;
|
||||
AlertNotificationService anService;
|
||||
AlertNotificationClient alertNotificationClient;
|
||||
CurrentTimeService currentTimeService;
|
||||
MusicService musicService;
|
||||
NavigationService navService;
|
||||
BatteryInformationService batteryInformationService;
|
||||
ImmediateAlertService immediateAlertService;
|
||||
HeartRateService heartRateService;
|
||||
DeviceInformationService deviceInformationService;
|
||||
CurrentTimeClient currentTimeClient;
|
||||
AlertNotificationService anService;
|
||||
AlertNotificationClient alertNotificationClient;
|
||||
CurrentTimeService currentTimeService;
|
||||
MusicService musicService;
|
||||
NavigationService navService;
|
||||
BatteryInformationService batteryInformationService;
|
||||
ImmediateAlertService immediateAlertService;
|
||||
HeartRateService heartRateService;
|
||||
|
||||
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
||||
uint16_t connectionHandle = 0;
|
||||
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
||||
uint16_t connectionHandle = 0;
|
||||
|
||||
ble_uuid128_t dfuServiceUuid {
|
||||
.u { .type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
|
||||
};
|
||||
ble_uuid128_t dfuServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}};
|
||||
|
||||
ServiceDiscovery serviceDiscovery;
|
||||
ServiceDiscovery serviceDiscovery;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,15 @@ using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr uint8_t NotificationManager::MessageSize;
|
||||
|
||||
|
||||
void NotificationManager::Push(NotificationManager::Notification &¬if) {
|
||||
void NotificationManager::Push(NotificationManager::Notification&& notif) {
|
||||
notif.id = GetNextId();
|
||||
notif.valid = true;
|
||||
notifications[writeIndex] = std::move(notif);
|
||||
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
||||
if(!empty)
|
||||
if (!empty)
|
||||
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
||||
else empty = false;
|
||||
else
|
||||
empty = false;
|
||||
|
||||
newNotification = true;
|
||||
}
|
||||
@ -30,40 +30,48 @@ NotificationManager::Notification::Id NotificationManager::GetNextId() {
|
||||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
||||
return n.valid && n.id == id;
|
||||
});
|
||||
if (currentIterator == notifications.end() || currentIterator->id != id)
|
||||
return Notification {};
|
||||
|
||||
auto& lastNotification = notifications[readIndex];
|
||||
|
||||
NotificationManager::Notification result;
|
||||
|
||||
if(currentIterator == (notifications.end()-1))
|
||||
if (currentIterator == (notifications.end() - 1))
|
||||
result = *(notifications.begin());
|
||||
else
|
||||
result = *(currentIterator+1);
|
||||
result = *(currentIterator + 1);
|
||||
|
||||
if(result.id <= id) return {};
|
||||
if (result.id <= id)
|
||||
return {};
|
||||
|
||||
result.index = (lastNotification.id - result.id)+1;
|
||||
result.index = (lastNotification.id - result.id) + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
||||
return n.valid && n.id == id;
|
||||
});
|
||||
if (currentIterator == notifications.end() || currentIterator->id != id)
|
||||
return Notification {};
|
||||
|
||||
auto& lastNotification = notifications[readIndex];
|
||||
|
||||
NotificationManager::Notification result;
|
||||
|
||||
if(currentIterator == notifications.begin())
|
||||
result = *(notifications.end()-1);
|
||||
if (currentIterator == notifications.begin())
|
||||
result = *(notifications.end() - 1);
|
||||
else
|
||||
result = *(currentIterator-1);
|
||||
result = *(currentIterator - 1);
|
||||
|
||||
if(result.id >= id) return {};
|
||||
if (result.id >= id)
|
||||
return {};
|
||||
|
||||
result.index = (lastNotification.id - result.id)+1;
|
||||
result.index = (lastNotification.id - result.id) + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -76,7 +84,7 @@ bool NotificationManager::IsVibrationEnabled() {
|
||||
}
|
||||
|
||||
void NotificationManager::ToggleVibrations() {
|
||||
vibrationEnabled = !vibrationEnabled;
|
||||
vibrationEnabled = !vibrationEnabled;
|
||||
}
|
||||
|
||||
bool NotificationManager::ClearNewNotificationFlag() {
|
||||
@ -84,21 +92,23 @@ bool NotificationManager::ClearNewNotificationFlag() {
|
||||
}
|
||||
|
||||
size_t NotificationManager::NbNotifications() const {
|
||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n){ return n.valid;});
|
||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
|
||||
return n.valid;
|
||||
});
|
||||
}
|
||||
|
||||
const char* NotificationManager::Notification::Message() const {
|
||||
const char* itField = std::find(message.begin(), message.begin()+size-1, '\0');
|
||||
if(itField != message.begin()+size-1) {
|
||||
const char* ptr = (itField)+1;
|
||||
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
|
||||
if (itField != message.begin() + size - 1) {
|
||||
const char* ptr = (itField) + 1;
|
||||
return ptr;
|
||||
}
|
||||
return const_cast<char*>(message.data());
|
||||
}
|
||||
|
||||
const char* NotificationManager::Notification::Title() const {
|
||||
const char * itField = std::find(message.begin(), message.begin()+size-1, '\0');
|
||||
if(itField != message.begin()+size-1) {
|
||||
const char* itField = std::find(message.begin(), message.begin() + size - 1, '\0');
|
||||
if (itField != message.begin() + size - 1) {
|
||||
return message.data();
|
||||
}
|
||||
return {};
|
||||
|
@ -8,23 +8,35 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class NotificationManager {
|
||||
public:
|
||||
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage };
|
||||
static constexpr uint8_t MessageSize{100};
|
||||
public:
|
||||
enum class Categories {
|
||||
Unknown,
|
||||
SimpleAlert,
|
||||
Email,
|
||||
News,
|
||||
IncomingCall,
|
||||
MissedCall,
|
||||
Sms,
|
||||
VoiceMail,
|
||||
Schedule,
|
||||
HighProriotyAlert,
|
||||
InstantMessage
|
||||
};
|
||||
static constexpr uint8_t MessageSize {100};
|
||||
|
||||
struct Notification {
|
||||
using Id = uint8_t;
|
||||
Id id;
|
||||
bool valid = false;
|
||||
uint8_t index;
|
||||
uint8_t size;
|
||||
std::array<char, MessageSize+1> message;
|
||||
Categories category = Categories::Unknown;
|
||||
struct Notification {
|
||||
using Id = uint8_t;
|
||||
Id id;
|
||||
bool valid = false;
|
||||
uint8_t index;
|
||||
uint8_t size;
|
||||
std::array<char, MessageSize + 1> message;
|
||||
Categories category = Categories::Unknown;
|
||||
|
||||
const char* Message() const;
|
||||
const char* Title() const;
|
||||
};
|
||||
Notification::Id nextId {0};
|
||||
const char* Message() const;
|
||||
const char* Title() const;
|
||||
};
|
||||
Notification::Id nextId {0};
|
||||
|
||||
void Push(Notification&& notif);
|
||||
Notification GetLastNotification();
|
||||
@ -35,18 +47,20 @@ namespace Pinetime {
|
||||
bool IsVibrationEnabled();
|
||||
void ToggleVibrations();
|
||||
|
||||
static constexpr size_t MaximumMessageSize() { return MessageSize; };
|
||||
static constexpr size_t MaximumMessageSize() {
|
||||
return MessageSize;
|
||||
};
|
||||
size_t NbNotifications() const;
|
||||
|
||||
private:
|
||||
Notification::Id GetNextId();
|
||||
static constexpr uint8_t TotalNbNotifications = 5;
|
||||
std::array<Notification, TotalNbNotifications> notifications;
|
||||
uint8_t readIndex = 0;
|
||||
uint8_t writeIndex = 0;
|
||||
bool empty = true;
|
||||
std::atomic<bool> newNotification{false};
|
||||
bool vibrationEnabled = true;
|
||||
private:
|
||||
Notification::Id GetNextId();
|
||||
static constexpr uint8_t TotalNbNotifications = 5;
|
||||
std::array<Notification, TotalNbNotifications> notifications;
|
||||
uint8_t readIndex = 0;
|
||||
uint8_t writeIndex = 0;
|
||||
bool empty = true;
|
||||
std::atomic<bool> newNotification {false};
|
||||
bool vibrationEnabled = true;
|
||||
};
|
||||
}
|
||||
}
|
@ -4,8 +4,7 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients{clients} {
|
||||
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients {clients} {
|
||||
}
|
||||
|
||||
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||
@ -16,7 +15,7 @@ void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||
|
||||
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
||||
clientIterator++;
|
||||
if(clientIterator != clients.end()) {
|
||||
if (clientIterator != clients.end()) {
|
||||
DiscoverNextService(connectionHandle);
|
||||
} else {
|
||||
NRF_LOG_INFO("End of service discovery");
|
||||
@ -26,7 +25,7 @@ void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
||||
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
|
||||
NRF_LOG_INFO("[Discovery] Discover next service");
|
||||
|
||||
auto discoverNextService = [this](uint16_t connectionHandle){
|
||||
auto discoverNextService = [this](uint16_t connectionHandle) {
|
||||
this->OnServiceDiscovered(connectionHandle);
|
||||
};
|
||||
(*clientIterator)->Discover(connectionHandle, discoverNextService);
|
||||
|
@ -8,17 +8,16 @@ namespace Pinetime {
|
||||
class BleClient;
|
||||
|
||||
class ServiceDiscovery {
|
||||
public:
|
||||
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
|
||||
public:
|
||||
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
|
||||
|
||||
void StartDiscovery(uint16_t connectionHandle);
|
||||
void StartDiscovery(uint16_t connectionHandle);
|
||||
|
||||
|
||||
private:
|
||||
BleClient** clientIterator;
|
||||
std::array<BleClient*, 2> clients;
|
||||
void OnServiceDiscovered(uint16_t connectionHandle);
|
||||
void DiscoverNextService(uint16_t connectionHandle);
|
||||
private:
|
||||
BleClient** clientIterator;
|
||||
std::array<BleClient*, 2> clients;
|
||||
void OnServiceDiscovered(uint16_t connectionHandle);
|
||||
void DiscoverNextService(uint16_t connectionHandle);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
||||
void BrightnessController::Init() {
|
||||
nrf_gpio_cfg_output(pinLcdBacklight1);
|
||||
nrf_gpio_cfg_output(pinLcdBacklight2);
|
||||
@ -14,7 +13,7 @@ void BrightnessController::Init() {
|
||||
|
||||
void BrightnessController::Set(BrightnessController::Levels level) {
|
||||
this->level = level;
|
||||
switch(level) {
|
||||
switch (level) {
|
||||
default:
|
||||
case Levels::High:
|
||||
nrf_gpio_pin_clear(pinLcdBacklight1);
|
||||
@ -40,20 +39,34 @@ void BrightnessController::Set(BrightnessController::Levels level) {
|
||||
}
|
||||
|
||||
void BrightnessController::Lower() {
|
||||
switch(level) {
|
||||
case Levels::High: Set(Levels::Medium); break;
|
||||
case Levels::Medium: Set(Levels::Low); break;
|
||||
case Levels::Low: Set(Levels::Off); break;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::High:
|
||||
Set(Levels::Medium);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
Set(Levels::Low);
|
||||
break;
|
||||
case Levels::Low:
|
||||
Set(Levels::Off);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BrightnessController::Higher() {
|
||||
switch(level) {
|
||||
case Levels::Off: Set(Levels::Low); break;
|
||||
case Levels::Low: Set(Levels::Medium); break;
|
||||
case Levels::Medium: Set(Levels::High); break;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::Off:
|
||||
Set(Levels::Low);
|
||||
break;
|
||||
case Levels::Low:
|
||||
Set(Levels::Medium);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
Set(Levels::High);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,29 +83,44 @@ void BrightnessController::Restore() {
|
||||
}
|
||||
|
||||
void BrightnessController::Step() {
|
||||
switch(level) {
|
||||
case Levels::Low: Set(Levels::Medium); break;
|
||||
case Levels::Medium: Set(Levels::High); break;
|
||||
case Levels::High: Set(Levels::Low); break;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::Low:
|
||||
Set(Levels::Medium);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
Set(Levels::High);
|
||||
break;
|
||||
case Levels::High:
|
||||
Set(Levels::Low);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* BrightnessController::GetIcon() {
|
||||
switch(level) {
|
||||
case Levels::Medium: return Applications::Screens::Symbols::brightnessMedium;
|
||||
case Levels::High: return Applications::Screens::Symbols::brightnessHigh;
|
||||
default: break;
|
||||
switch (level) {
|
||||
case Levels::Medium:
|
||||
return Applications::Screens::Symbols::brightnessMedium;
|
||||
case Levels::High:
|
||||
return Applications::Screens::Symbols::brightnessHigh;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Applications::Screens::Symbols::brightnessLow;
|
||||
}
|
||||
|
||||
const char* BrightnessController::ToString() {
|
||||
switch(level) {
|
||||
case Levels::Off: return "Off";
|
||||
case Levels::Low: return "Low";
|
||||
case Levels::Medium: return "Medium";
|
||||
case Levels::High: return "High";
|
||||
default : return "???";
|
||||
switch (level) {
|
||||
case Levels::Off:
|
||||
return "Off";
|
||||
case Levels::Low:
|
||||
return "Low";
|
||||
case Levels::Medium:
|
||||
return "Medium";
|
||||
case Levels::High:
|
||||
return "High";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class BrightnessController {
|
||||
public:
|
||||
enum class Levels {Off, Low, Medium, High};
|
||||
enum class Levels { Off, Low, Medium, High };
|
||||
void Init();
|
||||
|
||||
void Set(Levels level);
|
||||
|
@ -5,22 +5,21 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
DateTime::DateTime(System::SystemTask& systemTask) : systemTask{systemTask} {
|
||||
|
||||
DateTime::DateTime(System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
}
|
||||
|
||||
|
||||
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute,
|
||||
uint8_t second, uint32_t systickCounter) {
|
||||
std::tm tm = { /* .tm_sec = */ second,
|
||||
/* .tm_min = */ minute,
|
||||
/* .tm_hour = */ hour,
|
||||
/* .tm_mday = */ day,
|
||||
/* .tm_mon = */ month - 1,
|
||||
/* .tm_year = */ year - 1900,
|
||||
void DateTime::SetTime(
|
||||
uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
|
||||
std::tm tm = {
|
||||
/* .tm_sec = */ second,
|
||||
/* .tm_min = */ minute,
|
||||
/* .tm_hour = */ hour,
|
||||
/* .tm_mday = */ day,
|
||||
/* .tm_mon = */ month - 1,
|
||||
/* .tm_year = */ year - 1900,
|
||||
};
|
||||
tm.tm_isdst = -1; // Use DST value from local time zone
|
||||
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||
|
||||
NRF_LOG_INFO("%d %d %d ", day, month, year);
|
||||
NRF_LOG_INFO("%d %d %d ", hour, minute, second);
|
||||
@ -34,7 +33,7 @@ void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfW
|
||||
void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
// Handle systick counter overflow
|
||||
uint32_t systickDelta = 0;
|
||||
if(systickCounter < previousSystickCounter) {
|
||||
if (systickCounter < previousSystickCounter) {
|
||||
systickDelta = 0xffffff - previousSystickCounter;
|
||||
systickDelta += systickCounter + 1;
|
||||
} else {
|
||||
@ -42,11 +41,11 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 1000 ms = 1024 ticks
|
||||
*/
|
||||
* 1000 ms = 1024 ticks
|
||||
*/
|
||||
auto correctedDelta = systickDelta / 1024;
|
||||
auto rest = (systickDelta - (correctedDelta*1024));
|
||||
if(systickCounter >= rest) {
|
||||
auto rest = (systickDelta - (correctedDelta * 1024));
|
||||
if (systickCounter >= rest) {
|
||||
previousSystickCounter = systickCounter - rest;
|
||||
} else {
|
||||
previousSystickCounter = 0xffffff - (rest - systickCounter);
|
||||
@ -56,12 +55,12 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
uptime += std::chrono::seconds(correctedDelta);
|
||||
|
||||
auto dp = date::floor<date::days>(currentDateTime);
|
||||
auto time = date::make_time(currentDateTime-dp);
|
||||
auto time = date::make_time(currentDateTime - dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
year = (int)yearMonthDay.year();
|
||||
month = static_cast<Months>((unsigned)yearMonthDay.month());
|
||||
day = (unsigned)yearMonthDay.day();
|
||||
year = (int) yearMonthDay.year();
|
||||
month = static_cast<Months>((unsigned) yearMonthDay.month());
|
||||
day = (unsigned) yearMonthDay.day();
|
||||
dayOfWeek = static_cast<Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||
|
||||
hour = time.hours().count();
|
||||
@ -69,7 +68,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
second = time.seconds().count();
|
||||
|
||||
// Notify new day to SystemTask
|
||||
if(hour == 0 and not isMidnightAlreadyNotified) {
|
||||
if (hour == 0 and not isMidnightAlreadyNotified) {
|
||||
isMidnightAlreadyNotified = true;
|
||||
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
|
||||
} else if (hour != 0) {
|
||||
@ -77,123 +76,45 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *DateTime::MonthShortToString() {
|
||||
return DateTime::MonthsString[(uint8_t)month];
|
||||
const char* DateTime::MonthShortToString() {
|
||||
return DateTime::MonthsString[(uint8_t) month];
|
||||
}
|
||||
|
||||
const char *DateTime::MonthShortToStringLow() {
|
||||
return DateTime::MonthsStringLow[(uint8_t)month];
|
||||
const char* DateTime::MonthShortToStringLow() {
|
||||
return DateTime::MonthsStringLow[(uint8_t) month];
|
||||
}
|
||||
|
||||
const char *DateTime::MonthsToStringLow() {
|
||||
return DateTime::MonthsLow[(uint8_t)month];
|
||||
const char* DateTime::MonthsToStringLow() {
|
||||
return DateTime::MonthsLow[(uint8_t) month];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekToString() {
|
||||
return DateTime::DaysString[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekToString() {
|
||||
return DateTime::DaysString[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekShortToString() {
|
||||
return DateTime::DaysStringShort[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekShortToString() {
|
||||
return DateTime::DaysStringShort[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekToStringLow() {
|
||||
return DateTime::DaysStringLow[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekToStringLow() {
|
||||
return DateTime::DaysStringLow[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
const char *DateTime::DayOfWeekShortToStringLow() {
|
||||
return DateTime::DaysStringShortLow[(uint8_t)dayOfWeek];
|
||||
const char* DateTime::DayOfWeekShortToStringLow() {
|
||||
return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
||||
|
||||
char const *DateTime::DaysStringLow[] = {
|
||||
"--",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
};
|
||||
char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
|
||||
char const *DateTime::DaysStringShortLow[] = {
|
||||
"--",
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri",
|
||||
"Sat",
|
||||
"Sun"
|
||||
};
|
||||
char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
|
||||
char const *DateTime::DaysStringShort[] = {
|
||||
"--",
|
||||
"MON",
|
||||
"TUE",
|
||||
"WED",
|
||||
"THU",
|
||||
"FRI",
|
||||
"SAT",
|
||||
"SUN"
|
||||
};
|
||||
char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"};
|
||||
|
||||
char const *DateTime::DaysString[] = {
|
||||
"--",
|
||||
"MONDAY",
|
||||
"TUESDAY",
|
||||
"WEDNESDAY",
|
||||
"THURSDAY",
|
||||
"FRIDAY",
|
||||
"SATURDAY",
|
||||
"SUNDAY"
|
||||
};
|
||||
char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
||||
|
||||
char const *DateTime::MonthsString[] = {
|
||||
"--",
|
||||
"JAN",
|
||||
"FEB",
|
||||
"MAR",
|
||||
"APR",
|
||||
"MAY",
|
||||
"JUN",
|
||||
"JUL",
|
||||
"AUG",
|
||||
"SEP",
|
||||
"OCT",
|
||||
"NOV",
|
||||
"DEC"
|
||||
};
|
||||
char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
char const *DateTime::MonthsStringLow[] = {
|
||||
"--",
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
};
|
||||
|
||||
char const *DateTime::MonthsLow[] = {
|
||||
"--",
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
};
|
||||
char const* DateTime::MonthsLow[] = {
|
||||
"--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
|
@ -9,56 +9,95 @@ namespace Pinetime {
|
||||
}
|
||||
namespace Controllers {
|
||||
class DateTime {
|
||||
public:
|
||||
enum class Days : uint8_t {Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
|
||||
enum class Months : uint8_t {Unknown, January, February, March, April, May, June, July, August, September, October, November, December};
|
||||
public:
|
||||
enum class Days : uint8_t { Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
|
||||
enum class Months : uint8_t {
|
||||
Unknown,
|
||||
January,
|
||||
February,
|
||||
March,
|
||||
April,
|
||||
May,
|
||||
June,
|
||||
July,
|
||||
August,
|
||||
September,
|
||||
October,
|
||||
November,
|
||||
December
|
||||
};
|
||||
|
||||
DateTime(System::SystemTask& systemTask);
|
||||
DateTime(System::SystemTask& systemTask);
|
||||
|
||||
void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter);
|
||||
void UpdateTime(uint32_t systickCounter);
|
||||
uint16_t Year() const { return year; }
|
||||
Months Month() const { return month; }
|
||||
uint8_t Day() const { return day; }
|
||||
Days DayOfWeek() const { return dayOfWeek; }
|
||||
uint8_t Hours() const { return hour; }
|
||||
uint8_t Minutes() const { return minute; }
|
||||
uint8_t Seconds() const { return second; }
|
||||
void SetTime(uint16_t year,
|
||||
uint8_t month,
|
||||
uint8_t day,
|
||||
uint8_t dayOfWeek,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second,
|
||||
uint32_t systickCounter);
|
||||
void UpdateTime(uint32_t systickCounter);
|
||||
uint16_t Year() const {
|
||||
return year;
|
||||
}
|
||||
Months Month() const {
|
||||
return month;
|
||||
}
|
||||
uint8_t Day() const {
|
||||
return day;
|
||||
}
|
||||
Days DayOfWeek() const {
|
||||
return dayOfWeek;
|
||||
}
|
||||
uint8_t Hours() const {
|
||||
return hour;
|
||||
}
|
||||
uint8_t Minutes() const {
|
||||
return minute;
|
||||
}
|
||||
uint8_t Seconds() const {
|
||||
return second;
|
||||
}
|
||||
|
||||
const char *MonthShortToString();
|
||||
const char *MonthShortToStringLow();
|
||||
const char *MonthsToStringLow();
|
||||
const char *DayOfWeekToString();
|
||||
const char *DayOfWeekShortToString();
|
||||
const char *DayOfWeekToStringLow();
|
||||
const char *DayOfWeekShortToStringLow();
|
||||
const char* MonthShortToString();
|
||||
const char* MonthShortToStringLow();
|
||||
const char* MonthsToStringLow();
|
||||
const char* DayOfWeekToString();
|
||||
const char* DayOfWeekShortToString();
|
||||
const char* DayOfWeekToStringLow();
|
||||
const char* DayOfWeekShortToStringLow();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; }
|
||||
std::chrono::seconds Uptime() const { return uptime; }
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
uint16_t year = 0;
|
||||
Months month = Months::Unknown;
|
||||
uint8_t day = 0;
|
||||
Days dayOfWeek = Days::Unknown;
|
||||
uint8_t hour = 0;
|
||||
uint8_t minute = 0;
|
||||
uint8_t second = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
|
||||
return currentDateTime;
|
||||
}
|
||||
std::chrono::seconds Uptime() const {
|
||||
return uptime;
|
||||
}
|
||||
|
||||
uint32_t previousSystickCounter = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;
|
||||
std::chrono::seconds uptime {0};
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
uint16_t year = 0;
|
||||
Months month = Months::Unknown;
|
||||
uint8_t day = 0;
|
||||
Days dayOfWeek = Days::Unknown;
|
||||
uint8_t hour = 0;
|
||||
uint8_t minute = 0;
|
||||
uint8_t second = 0;
|
||||
|
||||
bool isMidnightAlreadyNotified = false;
|
||||
uint32_t previousSystickCounter = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;
|
||||
std::chrono::seconds uptime {0};
|
||||
|
||||
static char const *DaysString[];
|
||||
static char const *DaysStringShort[];
|
||||
static char const *DaysStringLow[];
|
||||
static char const *DaysStringShortLow[];
|
||||
static char const *MonthsString[];
|
||||
static char const *MonthsStringLow[];
|
||||
static char const *MonthsLow[];
|
||||
bool isMidnightAlreadyNotified = false;
|
||||
|
||||
static char const* DaysString[];
|
||||
static char const* DaysStringShort[];
|
||||
static char const* DaysStringLow[];
|
||||
static char const* DaysStringShortLow[];
|
||||
static char const* MonthsString[];
|
||||
static char const* MonthsStringLow[];
|
||||
static char const* MonthsLow[];
|
||||
};
|
||||
}
|
||||
}
|
@ -6,12 +6,12 @@
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
bool FirmwareValidator::IsValidated() const {
|
||||
auto* imageOkPtr = reinterpret_cast<uint32_t *>(validBitAdress);
|
||||
auto* imageOkPtr = reinterpret_cast<uint32_t*>(validBitAdress);
|
||||
return (*imageOkPtr) == validBitValue;
|
||||
}
|
||||
|
||||
void FirmwareValidator::Validate() {
|
||||
if(!IsValidated())
|
||||
if (!IsValidated())
|
||||
Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue);
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,15 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class FirmwareValidator {
|
||||
public:
|
||||
void Validate();
|
||||
bool IsValidated() const;
|
||||
public:
|
||||
void Validate();
|
||||
bool IsValidated() const;
|
||||
|
||||
void Reset();
|
||||
private:
|
||||
static constexpr uint32_t validBitAdress {0x7BFE8};
|
||||
static constexpr uint32_t validBitValue {1};
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
static constexpr uint32_t validBitAdress {0x7BFE8};
|
||||
static constexpr uint32_t validBitValue {1};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,10 @@
|
||||
#include "drivers/St7789.h"
|
||||
using namespace Pinetime::Components;
|
||||
|
||||
Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} {
|
||||
Gfx::Gfx(Pinetime::Drivers::St7789& lcd) : lcd {lcd} {
|
||||
}
|
||||
|
||||
void Gfx::Init() {
|
||||
|
||||
}
|
||||
|
||||
void Gfx::ClearScreen() {
|
||||
@ -17,10 +16,9 @@ void Gfx::ClearScreen() {
|
||||
state.busy = true;
|
||||
state.action = Action::FillRectangle;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t *>(buffer), width * 2);
|
||||
WaitTransferFinished();
|
||||
|
||||
lcd.DrawBuffer(0, 0, width, height, reinterpret_cast<const uint8_t*>(buffer), width * 2);
|
||||
WaitTransferFinished();
|
||||
}
|
||||
|
||||
void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
|
||||
@ -33,7 +31,7 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t col
|
||||
state.color = color;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(buffer), width * 2);
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(buffer), width * 2);
|
||||
|
||||
WaitTransferFinished();
|
||||
}
|
||||
@ -46,12 +44,12 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b)
|
||||
state.color = 0x00;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t *>(b), width * 2);
|
||||
lcd.DrawBuffer(x, y, w, h, reinterpret_cast<const uint8_t*>(b), width * 2);
|
||||
|
||||
WaitTransferFinished();
|
||||
}
|
||||
|
||||
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) {
|
||||
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap) {
|
||||
if (y > (height - p_font->height)) {
|
||||
// Not enough space to write even single char.
|
||||
return;
|
||||
@ -86,7 +84,7 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con
|
||||
}
|
||||
}
|
||||
|
||||
void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) {
|
||||
void Gfx::DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color) {
|
||||
uint8_t char_idx = c - font->startChar;
|
||||
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
|
||||
uint16_t bg = 0x0000;
|
||||
@ -100,10 +98,9 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
|
||||
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
||||
for (uint8_t k = 0; k < 8; k++) {
|
||||
if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
|
||||
buffer[(j*8)+k] = color;
|
||||
}
|
||||
else {
|
||||
buffer[(j*8)+k] = bg;
|
||||
buffer[(j * 8) + k] = color;
|
||||
} else {
|
||||
buffer[(j * 8) + k] = bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,12 +109,12 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint
|
||||
state.currentIteration = 0;
|
||||
state.busy = true;
|
||||
state.action = Action::DrawChar;
|
||||
state.font = const_cast<FONT_INFO *>(font);
|
||||
state.font = const_cast<FONT_INFO*>(font);
|
||||
state.character = c;
|
||||
state.color = color;
|
||||
state.taskToNotify = xTaskGetCurrentTaskHandle();
|
||||
|
||||
lcd.DrawBuffer(*x, y, bytes_in_line*8, font->height, reinterpret_cast<const uint8_t *>(&buffer), bytes_in_line*8*2);
|
||||
lcd.DrawBuffer(*x, y, bytes_in_line * 8, font->height, reinterpret_cast<const uint8_t*>(&buffer), bytes_in_line * 8 * 2);
|
||||
WaitTransferFinished();
|
||||
|
||||
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
|
||||
@ -136,13 +133,14 @@ void Gfx::Wakeup() {
|
||||
}
|
||||
|
||||
void Gfx::SetBackgroundColor(uint16_t color) {
|
||||
for(int i = 0; i < width; i++) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
buffer[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
||||
if(!state.busy) return false;
|
||||
bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
|
||||
if (!state.busy)
|
||||
return false;
|
||||
state.remainingIterations--;
|
||||
if (state.remainingIterations == 0) {
|
||||
state.busy = false;
|
||||
@ -150,27 +148,26 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(state.action == Action::FillRectangle) {
|
||||
*data = reinterpret_cast<uint8_t *>(buffer);
|
||||
if (state.action == Action::FillRectangle) {
|
||||
*data = reinterpret_cast<uint8_t*>(buffer);
|
||||
size = width * 2;
|
||||
} else if(state.action == Action::DrawChar) {
|
||||
} else if (state.action == Action::DrawChar) {
|
||||
uint16_t bg = 0x0000;
|
||||
uint8_t char_idx = state.character - state.font->startChar;
|
||||
uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
|
||||
|
||||
for (uint16_t j = 0; j < bytes_in_line; j++) {
|
||||
for (uint8_t k = 0; k < 8; k++) {
|
||||
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) {
|
||||
buffer[(j*8)+k] = state.color;
|
||||
}
|
||||
else {
|
||||
buffer[(j*8)+k] = bg;
|
||||
if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration + 1) * bytes_in_line) + j]) {
|
||||
buffer[(j * 8) + k] = state.color;
|
||||
} else {
|
||||
buffer[(j * 8) + k] = bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*data = reinterpret_cast<uint8_t *>(buffer);
|
||||
size = bytes_in_line*8*2;
|
||||
*data = reinterpret_cast<uint8_t*>(buffer);
|
||||
size = bytes_in_line * 8 * 2;
|
||||
}
|
||||
|
||||
state.currentIteration++;
|
||||
@ -179,7 +176,7 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
|
||||
}
|
||||
|
||||
void Gfx::NotifyEndOfTransfer(TaskHandle_t task) {
|
||||
if(task != nullptr) {
|
||||
if (task != nullptr) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
|
@ -12,49 +12,48 @@ namespace Pinetime {
|
||||
}
|
||||
namespace Components {
|
||||
class Gfx : public Pinetime::Drivers::BufferProvider {
|
||||
public:
|
||||
explicit Gfx(Drivers::St7789& lcd);
|
||||
void Init();
|
||||
void ClearScreen();
|
||||
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO *p_font, bool wrap);
|
||||
void DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color);
|
||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color);
|
||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b);
|
||||
void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
|
||||
void SetScrollStartLine(uint16_t line);
|
||||
public:
|
||||
explicit Gfx(Drivers::St7789& lcd);
|
||||
void Init();
|
||||
void ClearScreen();
|
||||
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap);
|
||||
void DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color);
|
||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color);
|
||||
void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b);
|
||||
void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines);
|
||||
void SetScrollStartLine(uint16_t line);
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
bool GetNextBuffer(uint8_t** buffer, size_t& size) override;
|
||||
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
bool GetNextBuffer(uint8_t **buffer, size_t &size) override;
|
||||
void pixel_draw(uint8_t x, uint8_t y, uint16_t color);
|
||||
private:
|
||||
static constexpr uint8_t width = 240;
|
||||
static constexpr uint8_t height = 240;
|
||||
|
||||
enum class Action { None, FillRectangle, DrawChar };
|
||||
struct State {
|
||||
State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} {
|
||||
}
|
||||
volatile bool busy;
|
||||
volatile Action action;
|
||||
volatile uint16_t remainingIterations;
|
||||
volatile uint16_t currentIteration;
|
||||
volatile FONT_INFO* font;
|
||||
volatile uint16_t color;
|
||||
volatile uint8_t character;
|
||||
volatile TaskHandle_t taskToNotify = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr uint8_t width = 240;
|
||||
static constexpr uint8_t height = 240;
|
||||
volatile State state;
|
||||
|
||||
enum class Action { None, FillRectangle, DrawChar};
|
||||
struct State {
|
||||
State() : busy{false}, action{Action::None}, remainingIterations{0}, currentIteration{0} {}
|
||||
volatile bool busy;
|
||||
volatile Action action;
|
||||
volatile uint16_t remainingIterations;
|
||||
volatile uint16_t currentIteration;
|
||||
volatile FONT_INFO *font;
|
||||
volatile uint16_t color;
|
||||
volatile uint8_t character;
|
||||
volatile TaskHandle_t taskToNotify = nullptr;
|
||||
};
|
||||
uint16_t buffer[width]; // 1 line buffer
|
||||
Drivers::St7789& lcd;
|
||||
|
||||
volatile State state;
|
||||
|
||||
uint16_t buffer[width]; // 1 line buffer
|
||||
Drivers::St7789& lcd;
|
||||
|
||||
void SetBackgroundColor(uint16_t color);
|
||||
void WaitTransferFinished() const;
|
||||
void NotifyEndOfTransfer(TaskHandle_t task);
|
||||
void SetBackgroundColor(uint16_t color);
|
||||
void WaitTransferFinished() const;
|
||||
void NotifyEndOfTransfer(TaskHandle_t task);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,7 @@
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0{b0}, b1{b1}, b2{b2}, a1{a1}, a2{a2} {
|
||||
|
||||
Biquad::Biquad(float b0, float b1, float b2, float a1, float a2) : b0 {b0}, b1 {b1}, b2 {b2}, a1 {a1}, a2 {a2} {
|
||||
}
|
||||
|
||||
float Biquad::Step(float x) {
|
||||
|
@ -5,7 +5,7 @@ namespace Pinetime {
|
||||
/// Direct Form II Biquad Filter
|
||||
class Biquad {
|
||||
public:
|
||||
Biquad(float b0, float b1, float b2, float a1, float a2);
|
||||
Biquad(float b0, float b1, float b2, float a1, float a2);
|
||||
float Step(float x);
|
||||
|
||||
private:
|
||||
|
@ -4,38 +4,35 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
HeartRateController::HeartRateController(Pinetime::System::SystemTask &systemTask) : systemTask{systemTask} {
|
||||
|
||||
HeartRateController::HeartRateController(Pinetime::System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
}
|
||||
|
||||
|
||||
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
|
||||
this->state = newState;
|
||||
if(this->heartRate != heartRate) {
|
||||
if (this->heartRate != heartRate) {
|
||||
this->heartRate = heartRate;
|
||||
service->OnNewHeartRateValue(heartRate);
|
||||
}
|
||||
}
|
||||
|
||||
void HeartRateController::Start() {
|
||||
if(task != nullptr) {
|
||||
if (task != nullptr) {
|
||||
state = States::NotEnoughData;
|
||||
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StartMeasurement);
|
||||
}
|
||||
}
|
||||
|
||||
void HeartRateController::Stop() {
|
||||
if(task != nullptr) {
|
||||
if (task != nullptr) {
|
||||
state = States::Stopped;
|
||||
task->PushMessage(Pinetime::Applications::HeartRateTask::Messages::StopMeasurement);
|
||||
}
|
||||
}
|
||||
|
||||
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask *task) {
|
||||
void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask* task) {
|
||||
this->task = task;
|
||||
}
|
||||
|
||||
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService *service) {
|
||||
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService* service) {
|
||||
this->service = service;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class HeartRateController {
|
||||
public:
|
||||
enum class States { Stopped, NotEnoughData, NoTouch, Running};
|
||||
enum class States { Stopped, NotEnoughData, NoTouch, Running };
|
||||
|
||||
explicit HeartRateController(System::SystemTask& systemTask);
|
||||
|
||||
@ -22,10 +22,14 @@ namespace Pinetime {
|
||||
void Update(States newState, uint8_t heartRate);
|
||||
|
||||
void SetHeartRateTask(Applications::HeartRateTask* task);
|
||||
States State() const { return state; }
|
||||
uint8_t HeartRate() const { return heartRate; }
|
||||
States State() const {
|
||||
return state;
|
||||
}
|
||||
uint8_t HeartRate() const {
|
||||
return heartRate;
|
||||
}
|
||||
|
||||
void SetService(Pinetime::Controllers::HeartRateService *service);
|
||||
void SetService(Pinetime::Controllers::HeartRateService* service);
|
||||
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
|
@ -11,25 +11,25 @@ using namespace Pinetime::Controllers;
|
||||
|
||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||
namespace {
|
||||
int Compare(int* d1, int* d2, size_t count) {
|
||||
int Compare(int8_t* d1, int8_t* d2, size_t count) {
|
||||
int e = 0;
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto d = d1[i] - d2[i];
|
||||
e += d * d;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
int CompareShift(int* d, int shift, size_t count) {
|
||||
return Compare(d +shift, d, count - shift);
|
||||
int CompareShift(int8_t* d, int shift, size_t count) {
|
||||
return Compare(d + shift, d, count - shift);
|
||||
}
|
||||
|
||||
int Trough(int* d, size_t size, float mn, float mx) {
|
||||
auto z2 = CompareShift(d, mn-2, size);
|
||||
auto z1 = CompareShift(d, mn-1, size);
|
||||
for(int i = mn; i < mx + 1; i++) {
|
||||
int Trough(int8_t* d, size_t size, uint8_t mn, uint8_t mx) {
|
||||
auto z2 = CompareShift(d, mn - 2, size);
|
||||
auto z1 = CompareShift(d, mn - 1, size);
|
||||
for (int i = mn; i < mx + 1; i++) {
|
||||
auto z = CompareShift(d, i, size);
|
||||
if(z2 > z1 && z1 < z)
|
||||
if (z2 > z1 && z1 < z)
|
||||
return i;
|
||||
z2 = z1;
|
||||
z1 = z;
|
||||
@ -38,28 +38,28 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
Ppg::Ppg(float spl) : offset{spl},
|
||||
hpf{0.87033078, -1.74066156, 0.87033078,-1.72377617, 0.75754694},
|
||||
agc{20, 0.971, 2},
|
||||
lpf{0.11595249, 0.23190498, 0.11595249,-0.72168143, 0.18549138} {
|
||||
|
||||
Ppg::Ppg(float spl)
|
||||
: offset {spl},
|
||||
hpf {0.87033078, -1.74066156, 0.87033078, -1.72377617, 0.75754694},
|
||||
agc {20, 0.971, 2},
|
||||
lpf {0.11595249, 0.23190498, 0.11595249, -0.72168143, 0.18549138} {
|
||||
}
|
||||
|
||||
int Ppg::Preprocess(float spl) {
|
||||
int8_t Ppg::Preprocess(float spl) {
|
||||
spl -= offset;
|
||||
spl = hpf.Step(spl);
|
||||
spl = agc.Step(spl);
|
||||
spl = lpf.Step(spl);
|
||||
|
||||
auto spl_int = static_cast<int>(spl);
|
||||
auto spl_int = static_cast<int8_t>(spl);
|
||||
|
||||
if(dataIndex < 200)
|
||||
if (dataIndex < 200)
|
||||
data[dataIndex++] = spl_int;
|
||||
return spl_int;
|
||||
}
|
||||
|
||||
float Ppg::HeartRate() {
|
||||
if(dataIndex < 200)
|
||||
if (dataIndex < 200)
|
||||
return 0;
|
||||
|
||||
NRF_LOG_INFO("PREPROCESS, offset = %d", offset);
|
||||
@ -71,26 +71,26 @@ float Ppg::HeartRate() {
|
||||
int cccount = 0;
|
||||
float Ppg::ProcessHeartRate() {
|
||||
|
||||
if(cccount > 2)
|
||||
if (cccount > 2)
|
||||
asm("nop");
|
||||
cccount ++;
|
||||
cccount++;
|
||||
auto t0 = Trough(data.data(), dataIndex, 7, 48);
|
||||
if(t0 < 0)
|
||||
if (t0 < 0)
|
||||
return 0;
|
||||
|
||||
float t1 = t0 * 2;
|
||||
t1 = Trough(data.data(), dataIndex, t1-5, t1+5);
|
||||
if(t1 < 0)
|
||||
t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5);
|
||||
if (t1 < 0)
|
||||
return 0;
|
||||
|
||||
float t2 = static_cast<int>(t1 * 3) / 2;
|
||||
t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5);
|
||||
if(t2 < 0)
|
||||
if (t2 < 0)
|
||||
return 0;
|
||||
|
||||
float t3 = static_cast<int>(t2 * 4) / 3;
|
||||
t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4);
|
||||
if(t3 < 0)
|
||||
if (t3 < 0)
|
||||
return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2);
|
||||
|
||||
return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3);
|
||||
|
@ -10,22 +10,21 @@ namespace Pinetime {
|
||||
public:
|
||||
explicit Ppg(float spl);
|
||||
|
||||
int Preprocess(float spl);
|
||||
int8_t Preprocess(float spl);
|
||||
float HeartRate();
|
||||
|
||||
void SetOffset(uint16_t i);
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
std::array<int, 200> data;
|
||||
std::array<int8_t, 200> data;
|
||||
size_t dataIndex = 0;
|
||||
float offset;
|
||||
Biquad hpf;
|
||||
Ptagc agc;
|
||||
Biquad lpf;
|
||||
|
||||
|
||||
float ProcessHeartRate();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,17 +10,16 @@
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
/** Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/ppg.py */
|
||||
Ptagc::Ptagc(float start, float decay, float threshold) : peak{start}, decay{decay}, boost{1.0f/decay}, threshold{threshold} {
|
||||
|
||||
Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {decay}, boost {1.0f / decay}, threshold {threshold} {
|
||||
}
|
||||
|
||||
float Ptagc::Step(float spl) {
|
||||
if(std::abs(spl) > peak)
|
||||
if (std::abs(spl) > peak)
|
||||
peak *= boost;
|
||||
else
|
||||
peak *= decay;
|
||||
|
||||
if((spl > (peak * threshold)) || (spl < (peak * -threshold)))
|
||||
if ((spl > (peak * threshold)) || (spl < (peak * -threshold)))
|
||||
return 0.0f;
|
||||
|
||||
spl = 100.0f * spl / (2.0f * peak);
|
||||
|
@ -12,7 +12,6 @@ namespace Pinetime {
|
||||
float decay;
|
||||
float boost;
|
||||
float threshold;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,24 @@ namespace Pinetime {
|
||||
public:
|
||||
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
|
||||
|
||||
uint16_t X() const { return x; }
|
||||
uint16_t Y() const { return y; }
|
||||
uint16_t Z() const { return z; }
|
||||
uint32_t NbSteps() const { return nbSteps; }
|
||||
int16_t X() const {
|
||||
return x;
|
||||
}
|
||||
int16_t Y() const {
|
||||
return y;
|
||||
}
|
||||
int16_t Z() const {
|
||||
return z;
|
||||
}
|
||||
uint32_t NbSteps() const {
|
||||
return nbSteps;
|
||||
}
|
||||
bool ShouldWakeUp(bool isSleeping);
|
||||
|
||||
void IsSensorOk(bool isOk);
|
||||
bool IsSensorOk() const { return isSensorOk; }
|
||||
bool IsSensorOk() const {
|
||||
return isSensorOk;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t nbSteps;
|
||||
|
@ -7,24 +7,25 @@ APP_TIMER_DEF(vibTimer);
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
MotorController::MotorController( Controllers::Settings &settingsController ) : settingsController{settingsController} {}
|
||||
MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
|
||||
}
|
||||
|
||||
void MotorController::Init() {
|
||||
nrf_gpio_cfg_output(pinMotor);
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
app_timer_init();
|
||||
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
|
||||
nrf_gpio_cfg_output(pinMotor);
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
app_timer_create(&vibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
|
||||
}
|
||||
|
||||
void MotorController::SetDuration(uint8_t motorDuration) {
|
||||
|
||||
if ( settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF ) return;
|
||||
|
||||
nrf_gpio_pin_clear(pinMotor);
|
||||
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
|
||||
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
|
||||
if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF)
|
||||
return;
|
||||
|
||||
nrf_gpio_pin_clear(pinMotor);
|
||||
/* Start timer for motorDuration miliseconds and timer triggers vibrate() when it finishes*/
|
||||
app_timer_start(vibTimer, APP_TIMER_TICKS(motorDuration), NULL);
|
||||
}
|
||||
|
||||
void MotorController::vibrate(void * p_context) {
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
void MotorController::vibrate(void* p_context) {
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
}
|
@ -9,14 +9,14 @@ namespace Pinetime {
|
||||
static constexpr uint8_t pinMotor = 16;
|
||||
|
||||
class MotorController {
|
||||
public:
|
||||
MotorController( Controllers::Settings &settingsController );
|
||||
void Init();
|
||||
void SetDuration(uint8_t motorDuration);
|
||||
public:
|
||||
MotorController(Controllers::Settings& settingsController);
|
||||
void Init();
|
||||
void SetDuration(uint8_t motorDuration);
|
||||
|
||||
private:
|
||||
Controllers::Settings& settingsController;
|
||||
static void vibrate(void * p_context);
|
||||
private:
|
||||
Controllers::Settings& settingsController;
|
||||
static void vibrate(void* p_context);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,16 @@
|
||||
|
||||
using namespace Pinetime::Tools;
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size) : buffer{buffer}, size{size} {
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t* buffer, size_t size) : buffer {buffer}, size {size} {
|
||||
}
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder{buffer, size} {
|
||||
RleDecoder::RleDecoder(const uint8_t* buffer, size_t size, uint16_t foregroundColor, uint16_t backgroundColor) : RleDecoder {buffer, size} {
|
||||
this->foregroundColor = foregroundColor;
|
||||
this->backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
|
||||
void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
||||
for (;encodedBufferIndex<size; encodedBufferIndex++) {
|
||||
void RleDecoder::DecodeNext(uint8_t* output, size_t maxBytes) {
|
||||
for (; encodedBufferIndex < size; encodedBufferIndex++) {
|
||||
uint8_t rl = buffer[encodedBufferIndex] - processedCount;
|
||||
while (rl) {
|
||||
output[bp] = color >> 8;
|
||||
@ -36,4 +34,3 @@ void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
||||
color = backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,110 +5,107 @@
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
struct SettingsHeader {
|
||||
uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive
|
||||
uint16_t version; // Current version, to verify if the saved data is for the current Version
|
||||
uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive
|
||||
uint16_t version; // Current version, to verify if the saved data is for the current Version
|
||||
};
|
||||
|
||||
#define HEADER_SIZE sizeof(SettingsHeader)
|
||||
|
||||
|
||||
Settings::Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash ) : spiNorFlash{spiNorFlash} {}
|
||||
Settings::Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
|
||||
}
|
||||
|
||||
void Settings::Init() {
|
||||
|
||||
// Load default settings from Flash
|
||||
LoadSettingsFromFlash();
|
||||
|
||||
// Load default settings from Flash
|
||||
LoadSettingsFromFlash();
|
||||
}
|
||||
|
||||
void Settings::SaveSettings() {
|
||||
|
||||
// verify if is necessary to save
|
||||
if ( settingsChanged ) {
|
||||
SaveSettingsToFlash();
|
||||
}
|
||||
settingsChanged = false;
|
||||
// verify if is necessary to save
|
||||
if (settingsChanged) {
|
||||
SaveSettingsToFlash();
|
||||
}
|
||||
settingsChanged = false;
|
||||
}
|
||||
|
||||
|
||||
bool Settings::FindHeader() {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
|
||||
for (uint8_t block = 0; block < 10; block++) {
|
||||
|
||||
spiNorFlash.Read( settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader) );
|
||||
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
|
||||
if ( settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion ) {
|
||||
settingsFlashBlock = block;
|
||||
return true;
|
||||
}
|
||||
for (uint8_t block = 0; block < 10; block++) {
|
||||
|
||||
spiNorFlash.Read(settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
|
||||
if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) {
|
||||
settingsFlashBlock = block;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Settings::ReadSettingsData() {
|
||||
uint8_t bufferSettings[sizeof(settings)];
|
||||
spiNorFlash.Read( settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings) );
|
||||
std::memcpy(&settings, bufferSettings, sizeof(settings));
|
||||
uint8_t bufferSettings[sizeof(settings)];
|
||||
spiNorFlash.Read(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||
std::memcpy(&settings, bufferSettings, sizeof(settings));
|
||||
}
|
||||
|
||||
void Settings::EraseBlock() {
|
||||
|
||||
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
|
||||
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
|
||||
}
|
||||
|
||||
void Settings::SetHeader( bool state ) {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
settingsHeader.isActive = state ? 0xF1 : 0xF0;
|
||||
settingsHeader.version = settingsVersion;
|
||||
|
||||
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||
void Settings::SetHeader(bool state) {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
settingsHeader.isActive = state ? 0xF1 : 0xF0;
|
||||
settingsHeader.version = settingsVersion;
|
||||
|
||||
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||
}
|
||||
|
||||
void Settings::SaveSettingsData() {
|
||||
uint8_t bufferSettings[sizeof(settings)];
|
||||
std::memcpy(bufferSettings, &settings, sizeof(settings));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||
uint8_t bufferSettings[sizeof(settings)];
|
||||
std::memcpy(bufferSettings, &settings, sizeof(settings));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||
}
|
||||
|
||||
void Settings::LoadSettingsFromFlash() {
|
||||
|
||||
if ( settingsFlashBlock == 99 ) {
|
||||
// Find current Block, if can't find use default settings and set block to 0 ans save !
|
||||
if ( FindHeader() ) {
|
||||
ReadSettingsData();
|
||||
} else {
|
||||
SaveSettingsToFlash();
|
||||
}
|
||||
if (settingsFlashBlock == 99) {
|
||||
// Find current Block, if can't find use default settings and set block to 0 ans save !
|
||||
if (FindHeader()) {
|
||||
ReadSettingsData();
|
||||
} else {
|
||||
// Read Settings from flash...
|
||||
// never used :)
|
||||
ReadSettingsData();
|
||||
SaveSettingsToFlash();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Read Settings from flash...
|
||||
// never used :)
|
||||
ReadSettingsData();
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::SaveSettingsToFlash() {
|
||||
|
||||
// calculate where to save...
|
||||
// mark current to inactive
|
||||
// erase the new location and save
|
||||
// set settingsFlashBlock
|
||||
|
||||
// if first time hever, only saves to block 0 and set settingsFlashBlock
|
||||
// calculate where to save...
|
||||
// mark current to inactive
|
||||
// erase the new location and save
|
||||
// set settingsFlashBlock
|
||||
|
||||
if ( settingsFlashBlock != 99 ) {
|
||||
SetHeader( false );
|
||||
}
|
||||
// if first time hever, only saves to block 0 and set settingsFlashBlock
|
||||
|
||||
settingsFlashBlock++;
|
||||
if ( settingsFlashBlock > 9 ) settingsFlashBlock = 0;
|
||||
if (settingsFlashBlock != 99) {
|
||||
SetHeader(false);
|
||||
}
|
||||
|
||||
EraseBlock();
|
||||
SetHeader( true );
|
||||
SaveSettingsData();
|
||||
settingsFlashBlock++;
|
||||
if (settingsFlashBlock > 9)
|
||||
settingsFlashBlock = 0;
|
||||
|
||||
EraseBlock();
|
||||
SetHeader(true);
|
||||
SaveSettingsData();
|
||||
}
|
||||
|
@ -8,98 +8,129 @@
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings {
|
||||
public:
|
||||
enum class ClockType {H24, H12};
|
||||
enum class Vibration {ON, OFF};
|
||||
enum class WakeUpMode {None, SingleTap, DoubleTap, RaiseWrist};
|
||||
public:
|
||||
enum class ClockType { H24, H12 };
|
||||
enum class Vibration { ON, OFF };
|
||||
enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist };
|
||||
|
||||
Settings( Pinetime::Drivers::SpiNorFlash &spiNorFlash );
|
||||
Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||
|
||||
void Init();
|
||||
void SaveSettings();
|
||||
void Init();
|
||||
void SaveSettings();
|
||||
|
||||
void SetClockFace( uint8_t face ) {
|
||||
if ( face != settings.clockFace ) settingsChanged = true;
|
||||
settings.clockFace = face;
|
||||
};
|
||||
uint8_t GetClockFace() const { return settings.clockFace; };
|
||||
void SetClockFace(uint8_t face) {
|
||||
if (face != settings.clockFace)
|
||||
settingsChanged = true;
|
||||
settings.clockFace = face;
|
||||
};
|
||||
uint8_t GetClockFace() const {
|
||||
return settings.clockFace;
|
||||
};
|
||||
|
||||
void SetAppMenu( uint8_t menu ) { appMenu = menu; };
|
||||
uint8_t GetAppMenu() { return appMenu; };
|
||||
void SetAppMenu(uint8_t menu) {
|
||||
appMenu = menu;
|
||||
};
|
||||
uint8_t GetAppMenu() {
|
||||
return appMenu;
|
||||
};
|
||||
|
||||
void SetSettingsMenu( uint8_t menu ) { settingsMenu = menu; };
|
||||
uint8_t GetSettingsMenu() const { return settingsMenu; };
|
||||
void SetSettingsMenu(uint8_t menu) {
|
||||
settingsMenu = menu;
|
||||
};
|
||||
uint8_t GetSettingsMenu() const {
|
||||
return settingsMenu;
|
||||
};
|
||||
|
||||
void SetClockType( ClockType clocktype ) {
|
||||
if ( clocktype != settings.clockType ) settingsChanged = true;
|
||||
settings.clockType = clocktype;
|
||||
};
|
||||
ClockType GetClockType() const { return settings.clockType; };
|
||||
void SetClockType(ClockType clocktype) {
|
||||
if (clocktype != settings.clockType)
|
||||
settingsChanged = true;
|
||||
settings.clockType = clocktype;
|
||||
};
|
||||
ClockType GetClockType() const {
|
||||
return settings.clockType;
|
||||
};
|
||||
|
||||
void SetVibrationStatus( Vibration status ) {
|
||||
if ( status != settings.vibrationStatus ) settingsChanged = true;
|
||||
settings.vibrationStatus = status;
|
||||
};
|
||||
Vibration GetVibrationStatus() const { return settings.vibrationStatus; };
|
||||
void SetVibrationStatus(Vibration status) {
|
||||
if (status != settings.vibrationStatus)
|
||||
settingsChanged = true;
|
||||
settings.vibrationStatus = status;
|
||||
};
|
||||
Vibration GetVibrationStatus() const {
|
||||
return settings.vibrationStatus;
|
||||
};
|
||||
|
||||
void SetScreenTimeOut( uint32_t timeout ) {
|
||||
if ( timeout != settings.screenTimeOut ) settingsChanged = true;
|
||||
settings.screenTimeOut = timeout;
|
||||
};
|
||||
uint32_t GetScreenTimeOut() const { return settings.screenTimeOut; };
|
||||
void SetScreenTimeOut(uint32_t timeout) {
|
||||
if (timeout != settings.screenTimeOut)
|
||||
settingsChanged = true;
|
||||
settings.screenTimeOut = timeout;
|
||||
};
|
||||
uint32_t GetScreenTimeOut() const {
|
||||
return settings.screenTimeOut;
|
||||
};
|
||||
|
||||
void setWakeUpMode( WakeUpMode wakeUp ) {
|
||||
if ( wakeUp != settings.wakeUpMode ) settingsChanged = true;
|
||||
settings.wakeUpMode = wakeUp;
|
||||
};
|
||||
WakeUpMode getWakeUpMode() const { return settings.wakeUpMode; };
|
||||
void setWakeUpMode(WakeUpMode wakeUp) {
|
||||
if (wakeUp != settings.wakeUpMode)
|
||||
settingsChanged = true;
|
||||
settings.wakeUpMode = wakeUp;
|
||||
};
|
||||
WakeUpMode getWakeUpMode() const {
|
||||
return settings.wakeUpMode;
|
||||
};
|
||||
|
||||
void SetBrightness( Controllers::BrightnessController::Levels level ) {
|
||||
if ( level != settings.brightLevel ) settingsChanged = true;
|
||||
settings.brightLevel = level;
|
||||
};
|
||||
Controllers::BrightnessController::Levels GetBrightness() const { return settings.brightLevel; };
|
||||
void SetBrightness(Controllers::BrightnessController::Levels level) {
|
||||
if (level != settings.brightLevel)
|
||||
settingsChanged = true;
|
||||
settings.brightLevel = level;
|
||||
};
|
||||
Controllers::BrightnessController::Levels GetBrightness() const {
|
||||
return settings.brightLevel;
|
||||
};
|
||||
|
||||
private:
|
||||
void SetStepsGoal( uint32_t goal ) {
|
||||
if ( goal != settings.stepsGoal )
|
||||
settingsChanged = true;
|
||||
settings.stepsGoal = goal;
|
||||
};
|
||||
|
||||
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
|
||||
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
struct SettingsData {
|
||||
private:
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
struct SettingsData {
|
||||
|
||||
ClockType clockType = ClockType::H24;
|
||||
Vibration vibrationStatus = Vibration::ON;
|
||||
ClockType clockType = ClockType::H24;
|
||||
Vibration vibrationStatus = Vibration::ON;
|
||||
|
||||
uint8_t clockFace = 0;
|
||||
uint8_t clockFace = 0;
|
||||
|
||||
uint32_t stepsGoal = 1000;
|
||||
uint32_t screenTimeOut = 15000;
|
||||
uint32_t stepsGoal = 10000;
|
||||
uint32_t screenTimeOut = 15000;
|
||||
|
||||
WakeUpMode wakeUpMode = WakeUpMode::None;
|
||||
WakeUpMode wakeUpMode = WakeUpMode::None;
|
||||
|
||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||
};
|
||||
|
||||
};
|
||||
SettingsData settings;
|
||||
bool settingsChanged = false;
|
||||
|
||||
SettingsData settings;
|
||||
bool settingsChanged = false;
|
||||
uint8_t appMenu = 0;
|
||||
uint8_t settingsMenu = 0;
|
||||
|
||||
uint8_t appMenu = 0;
|
||||
uint8_t settingsMenu = 0;
|
||||
// There are 10 blocks of reserved flash to save settings
|
||||
// to minimize wear, the recording is done in a rotating way by the 10 blocks
|
||||
uint8_t settingsFlashBlock = 99; // default to indicate it needs to find the active block
|
||||
|
||||
// There are 10 blocks of reserved flash to save settings
|
||||
// to minimize wear, the recording is done in a rotating way by the 10 blocks
|
||||
uint8_t settingsFlashBlock = 99; // default to indicate it needs to find the active block
|
||||
|
||||
static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location
|
||||
static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version
|
||||
|
||||
bool FindHeader();
|
||||
void ReadSettingsData();
|
||||
void EraseBlock();
|
||||
void SetHeader( bool state );
|
||||
void SaveSettingsData();
|
||||
void LoadSettingsFromFlash();
|
||||
void SaveSettingsToFlash();
|
||||
static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location
|
||||
static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version
|
||||
|
||||
bool FindHeader();
|
||||
void ReadSettingsData();
|
||||
void EraseBlock();
|
||||
void SetHeader(bool state);
|
||||
void SaveSettingsData();
|
||||
void LoadSettingsFromFlash();
|
||||
void SaveSettingsToFlash();
|
||||
};
|
||||
}
|
||||
}
|
64
src/components/timer/TimerController.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by florian on 16.05.21.
|
||||
//
|
||||
|
||||
#include "TimerController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "app_timer.h"
|
||||
#include "task.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
||||
APP_TIMER_DEF(timerAppTimer);
|
||||
|
||||
|
||||
TimerController::TimerController(System::SystemTask& systemTask) : systemTask{systemTask} {
|
||||
}
|
||||
|
||||
|
||||
void TimerController::Init() {
|
||||
app_timer_create(&timerAppTimer, APP_TIMER_MODE_SINGLE_SHOT, timerEnd);
|
||||
|
||||
}
|
||||
|
||||
void TimerController::StartTimer(uint32_t duration) {
|
||||
app_timer_stop(timerAppTimer);
|
||||
auto currentTicks = xTaskGetTickCount();
|
||||
app_timer_start(timerAppTimer, APP_TIMER_TICKS(duration), this);
|
||||
endTicks = currentTicks + APP_TIMER_TICKS(duration);
|
||||
timerRunning = true;
|
||||
}
|
||||
|
||||
uint32_t TimerController::GetTimeRemaining() {
|
||||
if (!timerRunning) {
|
||||
return 0;
|
||||
}
|
||||
auto currentTicks = xTaskGetTickCount();
|
||||
|
||||
TickType_t deltaTicks = 0;
|
||||
if (currentTicks > endTicks) {
|
||||
deltaTicks = 0xffffffff - currentTicks;
|
||||
deltaTicks += (endTicks + 1);
|
||||
} else {
|
||||
deltaTicks = endTicks - currentTicks;
|
||||
}
|
||||
|
||||
return (static_cast<TickType_t>(deltaTicks) / static_cast<TickType_t>(configTICK_RATE_HZ)) * 1000;
|
||||
}
|
||||
|
||||
void TimerController::timerEnd(void* p_context) {
|
||||
|
||||
auto* controller = static_cast<Controllers::TimerController*> (p_context);
|
||||
controller->timerRunning = false;
|
||||
controller->systemTask.PushMessage(System::SystemTask::Messages::OnTimerDone);
|
||||
}
|
||||
|
||||
void TimerController::StopTimer() {
|
||||
app_timer_stop(timerAppTimer);
|
||||
timerRunning = false;
|
||||
}
|
||||
|
||||
bool TimerController::IsRunning() {
|
||||
return timerRunning;
|
||||
}
|
36
src/components/timer/TimerController.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "app_timer.h"
|
||||
#include "portmacro_cmsis.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
|
||||
class TimerController {
|
||||
public:
|
||||
TimerController(Pinetime::System::SystemTask& systemTask);
|
||||
|
||||
void Init();
|
||||
|
||||
void StartTimer(uint32_t duration);
|
||||
|
||||
void StopTimer();
|
||||
|
||||
uint32_t GetTimeRemaining();
|
||||
|
||||
bool IsRunning();
|
||||
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
|
||||
static void timerEnd(void* p_context);
|
||||
|
||||
TickType_t endTicks;
|
||||
bool timerRunning = false;
|
||||
};
|
||||
}
|
||||
}
|
@ -3,9 +3,33 @@
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
enum class Apps {
|
||||
None, Launcher, Clock, SysInfo, FirmwareUpdate, FirmwareValidation, NotificationsPreview, Notifications, FlashLight, BatteryInfo,
|
||||
Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion,
|
||||
QuickSettings, Settings, SettingWatchFace, SettingTimeFormat, SettingDisplay, SettingWakeUp
|
||||
None,
|
||||
Launcher,
|
||||
Clock,
|
||||
SysInfo,
|
||||
FirmwareUpdate,
|
||||
FirmwareValidation,
|
||||
NotificationsPreview,
|
||||
Notifications,
|
||||
Timer,
|
||||
FlashLight,
|
||||
BatteryInfo,
|
||||
Music,
|
||||
Paint,
|
||||
Paddle,
|
||||
Twos,
|
||||
HeartRate,
|
||||
Navigation,
|
||||
StopWatch,
|
||||
Motion,
|
||||
Steps,
|
||||
QuickSettings,
|
||||
Settings,
|
||||
SettingWatchFace,
|
||||
SettingTimeFormat,
|
||||
SettingDisplay,
|
||||
SettingWakeUp,
|
||||
SettingSteps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,13 @@
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include <displayapp/screens/HeartRate.h>
|
||||
#include <displayapp/screens/Motion.h>
|
||||
#include <displayapp/screens/Timer.h>
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/motion/MotionController.h"
|
||||
#include "components/motor/MotorController.h"
|
||||
#include "displayapp/screens/ApplicationList.h"
|
||||
#include "displayapp/screens/Brightness.h"
|
||||
#include "displayapp/screens/Clock.h"
|
||||
@ -24,6 +26,7 @@
|
||||
#include "displayapp/screens/Twos.h"
|
||||
#include "displayapp/screens/FlashLight.h"
|
||||
#include "displayapp/screens/BatteryInfo.h"
|
||||
#include "displayapp/screens/Steps.h"
|
||||
|
||||
#include "drivers/Cst816s.h"
|
||||
#include "drivers/St7789.h"
|
||||
@ -36,49 +39,59 @@
|
||||
#include "displayapp/screens/settings/SettingTimeFormat.h"
|
||||
#include "displayapp/screens/settings/SettingWakeUp.h"
|
||||
#include "displayapp/screens/settings/SettingDisplay.h"
|
||||
#include "displayapp/screens/settings/SettingSteps.h"
|
||||
|
||||
using namespace Pinetime::Applications;
|
||||
using namespace Pinetime::Applications::Display;
|
||||
|
||||
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S& touchPanel,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController) :
|
||||
lcd{lcd},
|
||||
lvgl{lvgl},
|
||||
touchPanel{touchPanel},
|
||||
batteryController{batteryController},
|
||||
bleController{bleController},
|
||||
dateTimeController{dateTimeController},
|
||||
watchdog{watchdog},
|
||||
systemTask{systemTask},
|
||||
notificationManager{notificationManager},
|
||||
heartRateController{heartRateController},
|
||||
settingsController{settingsController},
|
||||
motionController{motionController} {
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController)
|
||||
: lcd {lcd},
|
||||
lvgl {lvgl},
|
||||
touchPanel {touchPanel},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
dateTimeController {dateTimeController},
|
||||
watchdog {watchdog},
|
||||
systemTask {systemTask},
|
||||
notificationManager {notificationManager},
|
||||
heartRateController {heartRateController},
|
||||
settingsController {settingsController},
|
||||
motorController {motorController},
|
||||
motionController {motionController},
|
||||
timerController {timerController} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
// Start clock when smartwatch boots
|
||||
LoadApp( Apps::Clock, DisplayApp::FullRefreshDirections::None );
|
||||
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle))
|
||||
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) {
|
||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayApp::Process(void *instance) {
|
||||
auto *app = static_cast<DisplayApp *>(instance);
|
||||
void DisplayApp::Process(void* instance) {
|
||||
auto* app = static_cast<DisplayApp*>(instance);
|
||||
NRF_LOG_INFO("displayapp task started!");
|
||||
app->InitHw();
|
||||
|
||||
// Send a dummy notification to unlock the lvgl display driver for the first iteration
|
||||
xTaskNotifyGive(xTaskGetCurrentTaskHandle());
|
||||
|
||||
while (1) {
|
||||
while (true) {
|
||||
app->Refresh();
|
||||
}
|
||||
}
|
||||
@ -112,7 +125,7 @@ void DisplayApp::Refresh() {
|
||||
switch (msg) {
|
||||
case Messages::GoToSleep:
|
||||
brightnessController.Backup();
|
||||
while(brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
brightnessController.Lower();
|
||||
vTaskDelay(100);
|
||||
}
|
||||
@ -127,30 +140,40 @@ void DisplayApp::Refresh() {
|
||||
break;
|
||||
case Messages::UpdateTimeOut:
|
||||
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
|
||||
break;
|
||||
break;
|
||||
case Messages::UpdateBleConnection:
|
||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected);
|
||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
|
||||
// Screens::Clock::BleConnectionStates::NotConnected);
|
||||
break;
|
||||
case Messages::UpdateBatteryLevel:
|
||||
batteryController.Update();
|
||||
break;
|
||||
case Messages::NewNotification:
|
||||
LoadApp( Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down );
|
||||
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case Messages::TimerDone:
|
||||
if (currentApp == Apps::Timer) {
|
||||
auto *timer = dynamic_cast<Screens::Timer*>(currentScreen.get());
|
||||
timer->setDone();
|
||||
} else {
|
||||
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
|
||||
}
|
||||
break;
|
||||
case Messages::TouchEvent: {
|
||||
if (state != States::Running) break;
|
||||
if (state != States::Running)
|
||||
break;
|
||||
auto gesture = OnTouchEvent();
|
||||
if(!currentScreen->OnTouchEvent(gesture)) {
|
||||
if ( currentApp == Apps::Clock ) {
|
||||
if (!currentScreen->OnTouchEvent(gesture)) {
|
||||
if (currentApp == Apps::Clock) {
|
||||
switch (gesture) {
|
||||
case TouchEvents::SwipeUp:
|
||||
LoadApp( Apps::Launcher, DisplayApp::FullRefreshDirections::Up );
|
||||
LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up);
|
||||
break;
|
||||
case TouchEvents::SwipeDown:
|
||||
LoadApp( Apps::Notifications, DisplayApp::FullRefreshDirections::Down );
|
||||
LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case TouchEvents::SwipeRight:
|
||||
LoadApp( Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim );
|
||||
LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
|
||||
break;
|
||||
case TouchEvents::DoubleTap:
|
||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||
@ -158,36 +181,35 @@ void DisplayApp::Refresh() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if ( returnTouchEvent == gesture ) {
|
||||
LoadApp( returnToApp, returnDirection );
|
||||
} else if (returnTouchEvent == gesture) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case Messages::ButtonPushed:
|
||||
if( currentApp == Apps::Clock ) {
|
||||
if (currentApp == Apps::Clock) {
|
||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||
} else {
|
||||
if ( !currentScreen->OnButtonPushed() ) {
|
||||
LoadApp( returnToApp, returnDirection );
|
||||
if (!currentScreen->OnButtonPushed()) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Messages::BleFirmwareUpdateStarted:
|
||||
LoadApp( Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down );
|
||||
LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case Messages::UpdateDateTime:
|
||||
// Added to remove warning
|
||||
// What should happen here?
|
||||
break;
|
||||
case Messages::UpdateDateTime:
|
||||
// Added to remove warning
|
||||
// What should happen here?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(state != States::Idle && touchMode == TouchModes::Polling) {
|
||||
if (state != States::Idle && touchMode == TouchModes::Polling) {
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
if(info.action == 2) {// 2 = contact
|
||||
if(!currentScreen->OnTouchEvent(info.x, info.y)) {
|
||||
if (info.action == 2) { // 2 = contact
|
||||
if (!currentScreen->OnTouchEvent(info.x, info.y)) {
|
||||
lvgl.SetNewTapEvent(info.x, info.y);
|
||||
}
|
||||
}
|
||||
@ -195,17 +217,17 @@ void DisplayApp::Refresh() {
|
||||
}
|
||||
|
||||
void DisplayApp::RunningState() {
|
||||
if(!currentScreen->Refresh()) {
|
||||
LoadApp( returnToApp, returnDirection );
|
||||
if (!currentScreen->Refresh()) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
}
|
||||
lv_task_handler();
|
||||
}
|
||||
|
||||
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||
LoadApp( app, direction );
|
||||
LoadApp(app, direction);
|
||||
}
|
||||
|
||||
void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
|
||||
void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
|
||||
returnToApp = app;
|
||||
returnDirection = direction;
|
||||
returnTouchEvent = touchEvent;
|
||||
@ -213,76 +235,94 @@ void DisplayApp::returnApp(Apps app, DisplayApp::FullRefreshDirections direction
|
||||
|
||||
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||
currentScreen.reset(nullptr);
|
||||
SetFullRefresh( direction );
|
||||
SetFullRefresh(direction);
|
||||
|
||||
// default return to launcher
|
||||
returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
|
||||
switch(app) {
|
||||
switch (app) {
|
||||
case Apps::Launcher:
|
||||
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::None:
|
||||
case Apps::Clock:
|
||||
currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController, motionController);
|
||||
currentScreen = std::make_unique<Screens::Clock>(this,
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
break;
|
||||
|
||||
case Apps::FirmwareValidation:
|
||||
currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::FirmwareUpdate:
|
||||
currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController);
|
||||
break;
|
||||
|
||||
case Apps::Notifications:
|
||||
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
currentScreen = std::make_unique<Screens::Notifications>(
|
||||
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
break;
|
||||
case Apps::NotificationsPreview:
|
||||
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
currentScreen = std::make_unique<Screens::Notifications>(
|
||||
this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
break;
|
||||
case Apps::Timer:
|
||||
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
|
||||
break;
|
||||
|
||||
// Settings
|
||||
case Apps::QuickSettings:
|
||||
currentScreen = std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
|
||||
currentScreen = std::make_unique<Screens::QuickSettings>(
|
||||
this, batteryController, dateTimeController, brightnessController, motorController, settingsController);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
|
||||
break;
|
||||
case Apps::Settings:
|
||||
currentScreen = std::make_unique<Screens::Settings>(this, settingsController);
|
||||
returnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SettingWatchFace:
|
||||
currentScreen = std::make_unique<Screens::SettingWatchFace>(this, settingsController);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SettingTimeFormat:
|
||||
currentScreen = std::make_unique<Screens::SettingTimeFormat>(this, settingsController);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SettingWakeUp:
|
||||
currentScreen = std::make_unique<Screens::SettingWakeUp>(this, settingsController);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SettingDisplay:
|
||||
currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SettingSteps:
|
||||
currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::BatteryInfo:
|
||||
currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SysInfo:
|
||||
currentScreen = std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
||||
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
currentScreen =
|
||||
std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
//
|
||||
//
|
||||
|
||||
case Apps::FlashLight:
|
||||
currentScreen = std::make_unique<Screens::FlashLight>(this, systemTask, brightnessController);
|
||||
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
|
||||
break;
|
||||
case Apps::StopWatch:
|
||||
currentScreen = std::make_unique<Screens::StopWatch>(this);
|
||||
@ -308,12 +348,14 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||
case Apps::Motion:
|
||||
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
|
||||
break;
|
||||
case Apps::Steps:
|
||||
currentScreen = std::make_unique<Screens::Steps>(this, motionController, settingsController);
|
||||
break;
|
||||
}
|
||||
currentApp = app;
|
||||
}
|
||||
|
||||
void DisplayApp::IdleState() {
|
||||
|
||||
}
|
||||
|
||||
void DisplayApp::PushMessage(Messages msg) {
|
||||
@ -328,11 +370,12 @@ void DisplayApp::PushMessage(Messages msg) {
|
||||
|
||||
TouchEvents DisplayApp::OnTouchEvent() {
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
if(info.isTouch) {
|
||||
switch(info.gesture) {
|
||||
if (info.isTouch) {
|
||||
switch (info.gesture) {
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
||||
if(touchMode == TouchModes::Gestures)
|
||||
if (touchMode == TouchModes::Gestures) {
|
||||
lvgl.SetNewTapEvent(info.x, info.y);
|
||||
}
|
||||
return TouchEvents::Tap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
||||
return TouchEvents::LongTap;
|
||||
@ -355,7 +398,7 @@ TouchEvents DisplayApp::OnTouchEvent() {
|
||||
}
|
||||
|
||||
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||
switch(direction){
|
||||
switch (direction) {
|
||||
case DisplayApp::FullRefreshDirections::Down:
|
||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
|
||||
break;
|
||||
@ -374,11 +417,11 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||
case DisplayApp::FullRefreshDirections::RightAnim:
|
||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
|
||||
touchMode = mode;
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,11 @@
|
||||
#include "LittleVgl.h"
|
||||
#include "TouchEvents.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
#include "components/motor/MotorController.h"
|
||||
#include "components/firmwarevalidator/FirmwareValidator.h"
|
||||
#include "components/settings/Settings.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "components/timer/TimerController.h"
|
||||
#include "Messages.h"
|
||||
|
||||
namespace Pinetime {
|
||||
@ -35,74 +37,77 @@ namespace Pinetime {
|
||||
};
|
||||
namespace Applications {
|
||||
class DisplayApp {
|
||||
public:
|
||||
enum class States {Idle, Running};
|
||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||
enum class TouchModes { Gestures, Polling };
|
||||
public:
|
||||
enum class States { Idle, Running };
|
||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||
enum class TouchModes { Gestures, Polling };
|
||||
|
||||
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController
|
||||
);
|
||||
void Start();
|
||||
void PushMessage(Display::Messages msg);
|
||||
DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S&,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController);
|
||||
void Start();
|
||||
void PushMessage(Display::Messages msg);
|
||||
|
||||
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
void SetTouchMode(TouchModes mode);
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
void SetTouchMode(TouchModes mode);
|
||||
|
||||
private:
|
||||
private:
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Components::LittleVgl& lvgl;
|
||||
Pinetime::Drivers::Cst816S& touchPanel;
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
Pinetime::Drivers::WatchdogView& watchdog;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
Pinetime::Controllers::HeartRateController& heartRateController;
|
||||
Pinetime::Controllers::Settings& settingsController;
|
||||
Pinetime::Controllers::MotorController& motorController;
|
||||
Pinetime::Controllers::MotionController& motionController;
|
||||
Pinetime::Controllers::TimerController& timerController;
|
||||
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Components::LittleVgl& lvgl;
|
||||
Pinetime::Drivers::Cst816S& touchPanel;
|
||||
Pinetime::Controllers::Battery &batteryController;
|
||||
Pinetime::Controllers::Ble &bleController;
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
Pinetime::Drivers::WatchdogView& watchdog;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
Pinetime::Controllers::HeartRateController& heartRateController;
|
||||
Pinetime::Controllers::Settings& settingsController;
|
||||
Pinetime::Controllers::MotionController& motionController;
|
||||
Pinetime::Controllers::FirmwareValidator validator;
|
||||
Controllers::BrightnessController brightnessController;
|
||||
|
||||
Pinetime::Controllers::FirmwareValidator validator;
|
||||
Controllers::BrightnessController brightnessController;
|
||||
TaskHandle_t taskHandle;
|
||||
|
||||
TaskHandle_t taskHandle;
|
||||
States state = States::Running;
|
||||
QueueHandle_t msgQueue;
|
||||
|
||||
States state = States::Running;
|
||||
QueueHandle_t msgQueue;
|
||||
static constexpr uint8_t queueSize = 10;
|
||||
static constexpr uint8_t itemSize = 1;
|
||||
|
||||
static constexpr uint8_t queueSize = 10;
|
||||
static constexpr uint8_t itemSize = 1;
|
||||
std::unique_ptr<Screens::Screen> currentScreen;
|
||||
|
||||
std::unique_ptr<Screens::Screen> currentScreen;
|
||||
Apps currentApp = Apps::None;
|
||||
Apps returnToApp = Apps::None;
|
||||
FullRefreshDirections returnDirection = FullRefreshDirections::None;
|
||||
TouchEvents returnTouchEvent = TouchEvents::None;
|
||||
|
||||
Apps currentApp = Apps::None;
|
||||
Apps returnToApp = Apps::None;
|
||||
FullRefreshDirections returnDirection = FullRefreshDirections::None;
|
||||
TouchEvents returnTouchEvent = TouchEvents::None;
|
||||
|
||||
TouchModes touchMode = TouchModes::Gestures;
|
||||
|
||||
TouchEvents OnTouchEvent();
|
||||
void RunningState();
|
||||
void IdleState();
|
||||
static void Process(void* instance);
|
||||
void InitHw();
|
||||
void Refresh();
|
||||
void returnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent);
|
||||
void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||
TouchModes touchMode = TouchModes::Gestures;
|
||||
|
||||
TouchEvents OnTouchEvent();
|
||||
void RunningState();
|
||||
void IdleState();
|
||||
static void Process(void* instance);
|
||||
void InitHw();
|
||||
void Refresh();
|
||||
void ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent);
|
||||
void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,17 +7,21 @@
|
||||
|
||||
using namespace Pinetime::Applications;
|
||||
|
||||
DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &touchPanel,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S& touchPanel,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotionController& motionController):
|
||||
lcd{lcd}, bleController{bleController} {
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController)
|
||||
: lcd {lcd}, bleController {bleController} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
|
||||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
@ -25,15 +29,15 @@ void DisplayApp::Start() {
|
||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
|
||||
void DisplayApp::Process(void *instance) {
|
||||
auto *app = static_cast<DisplayApp *>(instance);
|
||||
void DisplayApp::Process(void* instance) {
|
||||
auto* app = static_cast<DisplayApp*>(instance);
|
||||
NRF_LOG_INFO("displayapp task started!");
|
||||
|
||||
// Send a dummy notification to unlock the lvgl display driver for the first iteration
|
||||
xTaskNotifyGive(xTaskGetCurrentTaskHandle());
|
||||
|
||||
app->InitHw();
|
||||
while (1) {
|
||||
while (true) {
|
||||
app->Refresh();
|
||||
}
|
||||
}
|
||||
@ -47,10 +51,11 @@ void DisplayApp::Refresh() {
|
||||
if (xQueueReceive(msgQueue, &msg, 200)) {
|
||||
switch (msg) {
|
||||
case Display::Messages::UpdateBleConnection:
|
||||
if (bleController.IsConnected())
|
||||
if (bleController.IsConnected()) {
|
||||
DisplayLogo(colorBlue);
|
||||
else
|
||||
} else {
|
||||
DisplayLogo(colorWhite);
|
||||
}
|
||||
break;
|
||||
case Display::Messages::BleFirmwareUpdateStarted:
|
||||
DisplayLogo(colorGreen);
|
||||
@ -61,8 +66,9 @@ void DisplayApp::Refresh() {
|
||||
}
|
||||
|
||||
if (bleController.IsFirmwareUpdating()) {
|
||||
uint8_t percent = (static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) /
|
||||
static_cast<float>(bleController.FirmwareUpdateTotalBytes())) * 100.0f;
|
||||
uint8_t percent =
|
||||
(static_cast<float>(bleController.FirmwareUpdateCurrentBytes()) / static_cast<float>(bleController.FirmwareUpdateTotalBytes())) *
|
||||
100.0f;
|
||||
switch (bleController.State()) {
|
||||
case Controllers::Ble::FirmwareUpdateStates::Running:
|
||||
DisplayOtaProgress(percent, colorWhite);
|
||||
@ -81,20 +87,20 @@ void DisplayApp::Refresh() {
|
||||
|
||||
void DisplayApp::DisplayLogo(uint16_t color) {
|
||||
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
|
||||
for(int i = 0; i < displayWidth; i++) {
|
||||
for (int i = 0; i < displayWidth; i++) {
|
||||
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
|
||||
ulTaskNotifyTake(pdTRUE, 500);
|
||||
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel);
|
||||
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
|
||||
const uint8_t barHeight = 20;
|
||||
std::fill(displayBuffer, displayBuffer+(displayWidth * bytesPerPixel), color);
|
||||
for(int i = 0; i < barHeight; i++) {
|
||||
std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
|
||||
for (int i = 0; i < barHeight; i++) {
|
||||
ulTaskNotifyTake(pdTRUE, 500);
|
||||
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
|
||||
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel);
|
||||
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <drivers/Watchdog.h>
|
||||
#include <components/heartrate/HeartRateController.h>
|
||||
#include <components/motion/MotionController.h>
|
||||
#include <components/motor/MotorController.h>
|
||||
#include <components/settings/Settings.h>
|
||||
#include "TouchEvents.h"
|
||||
#include "Apps.h"
|
||||
@ -30,13 +31,18 @@ namespace Pinetime {
|
||||
namespace Applications {
|
||||
class DisplayApp {
|
||||
public:
|
||||
DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Drivers::Cst816S &,
|
||||
Controllers::Battery &batteryController, Controllers::Ble &bleController,
|
||||
Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog,
|
||||
System::SystemTask &systemTask,
|
||||
DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S&,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController);
|
||||
void Start();
|
||||
void PushMessage(Pinetime::Applications::Display::Messages msg);
|
||||
@ -49,7 +55,7 @@ namespace Pinetime {
|
||||
void InitHw();
|
||||
void Refresh();
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Controllers::Ble &bleController;
|
||||
Controllers::Ble& bleController;
|
||||
|
||||
static constexpr uint8_t queueSize = 10;
|
||||
static constexpr uint8_t itemSize = 1;
|
||||
@ -66,10 +72,6 @@ namespace Pinetime {
|
||||
static constexpr uint16_t colorRedSwapped = 0x00ff;
|
||||
static constexpr uint16_t colorBlack = 0x0000;
|
||||
uint8_t displayBuffer[displayWidth * bytesPerPixel];
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,22 +9,25 @@
|
||||
namespace Pinetime {
|
||||
namespace Components {
|
||||
class LittleVgl {
|
||||
public:
|
||||
enum class FullRefreshDirections { None, Up, Down };
|
||||
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {}
|
||||
|
||||
LittleVgl(const LittleVgl&) = delete;
|
||||
LittleVgl& operator=(const LittleVgl&) = delete;
|
||||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
|
||||
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p) {}
|
||||
bool GetTouchPadInfo(lv_indev_data_t *ptr) {return false;}
|
||||
void SetFullRefresh(FullRefreshDirections direction) {}
|
||||
void SetNewTapEvent(uint16_t x, uint16_t y) {}
|
||||
public:
|
||||
enum class FullRefreshDirections { None, Up, Down };
|
||||
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) {
|
||||
}
|
||||
|
||||
LittleVgl(const LittleVgl&) = delete;
|
||||
LittleVgl& operator=(const LittleVgl&) = delete;
|
||||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
|
||||
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
||||
}
|
||||
bool GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||
return false;
|
||||
}
|
||||
void SetFullRefresh(FullRefreshDirections direction) {
|
||||
}
|
||||
void SetNewTapEvent(uint16_t x, uint16_t y) {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,17 +11,18 @@ using namespace Pinetime::Components;
|
||||
|
||||
lv_style_t* LabelBigStyle = nullptr;
|
||||
|
||||
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
|
||||
static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) {
|
||||
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
||||
lvgl->FlushDisplay(area, color_p);
|
||||
}
|
||||
|
||||
bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) {
|
||||
bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
|
||||
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
|
||||
return lvgl->GetTouchPadInfo(data);
|
||||
}
|
||||
|
||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) : lcd{lcd}, touchPanel{touchPanel}, previousClick{0,0} {
|
||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
|
||||
: lcd {lcd}, touchPanel {touchPanel}, previousClick {0, 0} {
|
||||
lv_init();
|
||||
InitTheme();
|
||||
InitDisplay();
|
||||
@ -29,8 +30,8 @@ LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S&
|
||||
}
|
||||
|
||||
void LittleVgl::InitDisplay() {
|
||||
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 4); /*Initialize the display buffer*/
|
||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 4); /*Initialize the display buffer*/
|
||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||
|
||||
/*Set up the functions to access to your display*/
|
||||
|
||||
@ -59,7 +60,7 @@ void LittleVgl::InitTouchpad() {
|
||||
}
|
||||
|
||||
void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
||||
if(scrollDirection == FullRefreshDirections::None) {
|
||||
if (scrollDirection == FullRefreshDirections::None) {
|
||||
scrollDirection = direction;
|
||||
if (scrollDirection == FullRefreshDirections::Down) {
|
||||
lv_disp_set_direction(lv_disp_get_default(), 1);
|
||||
@ -75,16 +76,16 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
||||
}
|
||||
}
|
||||
|
||||
void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
||||
uint16_t y1, y2, width, height = 0;
|
||||
|
||||
ulTaskNotifyTake(pdTRUE, 200);
|
||||
// NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
|
||||
// which cannot be set/clear during a transfert.
|
||||
|
||||
if( (scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
||||
|
||||
if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
||||
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
|
||||
} else if( (scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0) ) {
|
||||
} else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
|
||||
writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
|
||||
}
|
||||
|
||||
@ -94,11 +95,11 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||
width = (area->x2 - area->x1) + 1;
|
||||
height = (area->y2 - area->y1) + 1;
|
||||
|
||||
if(scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
||||
if (scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
||||
|
||||
if(area->y2 < visibleNbLines - 1) {
|
||||
if (area->y2 < visibleNbLines - 1) {
|
||||
uint16_t toScroll = 0;
|
||||
if(area->y1 == 0) {
|
||||
if (area->y1 == 0) {
|
||||
toScroll = height * 2;
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
@ -106,19 +107,19 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||
toScroll = height;
|
||||
}
|
||||
|
||||
if(scrollOffset >= toScroll)
|
||||
if (scrollOffset >= toScroll)
|
||||
scrollOffset -= toScroll;
|
||||
else {
|
||||
toScroll -= scrollOffset;
|
||||
scrollOffset = (totalNbLines) - toScroll;
|
||||
scrollOffset = (totalNbLines) -toScroll;
|
||||
}
|
||||
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||
}
|
||||
|
||||
} else if(scrollDirection == FullRefreshDirections::Up) {
|
||||
} else if (scrollDirection == FullRefreshDirections::Up) {
|
||||
|
||||
if(area->y1 > 0) {
|
||||
if(area->y2 == visibleNbLines - 1) {
|
||||
if (area->y1 > 0) {
|
||||
if (area->y2 == visibleNbLines - 1) {
|
||||
scrollOffset += (height * 2);
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
@ -128,13 +129,13 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||
scrollOffset = scrollOffset % totalNbLines;
|
||||
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||
}
|
||||
} else if(scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||
if(area->x2 == visibleNbLines - 1) {
|
||||
} else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||
if (area->x2 == visibleNbLines - 1) {
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
}
|
||||
} else if(scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
||||
if(area->x1 == 0) {
|
||||
} else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
||||
if (area->x1 == 0) {
|
||||
scrollDirection = FullRefreshDirections::None;
|
||||
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||
}
|
||||
@ -143,17 +144,17 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
|
||||
if (y2 < y1) {
|
||||
height = totalNbLines - y1;
|
||||
|
||||
if ( height > 0 ) {
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
|
||||
if (height > 0) {
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||
ulTaskNotifyTake(pdTRUE, 100);
|
||||
}
|
||||
|
||||
|
||||
uint16_t pixOffset = width * height;
|
||||
height = y2 + 1;
|
||||
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t *>(color_p + pixOffset), width * height * 2);
|
||||
lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t*>(color_p + pixOffset), width * height * 2);
|
||||
|
||||
} else {
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
|
||||
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||
}
|
||||
|
||||
// IMPORTANT!!!
|
||||
@ -167,8 +168,8 @@ void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) {
|
||||
tapped = true;
|
||||
}
|
||||
|
||||
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
|
||||
if(tapped) {
|
||||
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||
if (tapped) {
|
||||
ptr->point.x = tap_x;
|
||||
ptr->point.y = tap_y;
|
||||
ptr->state = LV_INDEV_STATE_PR;
|
||||
@ -202,14 +203,8 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
|
||||
|
||||
void LittleVgl::InitTheme() {
|
||||
|
||||
lv_theme_t * th = lv_pinetime_theme_init(
|
||||
LV_COLOR_WHITE, LV_COLOR_SILVER,
|
||||
0,
|
||||
&jetbrains_mono_bold_20,
|
||||
&jetbrains_mono_bold_20,
|
||||
&jetbrains_mono_bold_20,
|
||||
&jetbrains_mono_bold_20);
|
||||
lv_theme_t* th = lv_pinetime_theme_init(
|
||||
LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
|
||||
|
||||
lv_theme_set_act(th);
|
||||
|
||||
}
|
||||
|
@ -10,50 +10,49 @@ namespace Pinetime {
|
||||
|
||||
namespace Components {
|
||||
class LittleVgl {
|
||||
public:
|
||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
|
||||
public:
|
||||
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
|
||||
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
|
||||
|
||||
LittleVgl(const LittleVgl&) = delete;
|
||||
LittleVgl& operator=(const LittleVgl&) = delete;
|
||||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
LittleVgl(const LittleVgl&) = delete;
|
||||
LittleVgl& operator=(const LittleVgl&) = delete;
|
||||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
|
||||
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p);
|
||||
bool GetTouchPadInfo(lv_indev_data_t *ptr);
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
void SetNewTapEvent(uint16_t x, uint16_t y);
|
||||
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
|
||||
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
void SetNewTapEvent(uint16_t x, uint16_t y);
|
||||
|
||||
private:
|
||||
void InitDisplay();
|
||||
void InitTouchpad();
|
||||
void InitTheme();
|
||||
private:
|
||||
void InitDisplay();
|
||||
void InitTouchpad();
|
||||
void InitTheme();
|
||||
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Drivers::Cst816S& touchPanel;
|
||||
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Drivers::Cst816S& touchPanel;
|
||||
lv_disp_buf_t disp_buf_2;
|
||||
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
|
||||
lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
|
||||
|
||||
lv_disp_drv_t disp_drv;
|
||||
lv_point_t previousClick;
|
||||
|
||||
lv_disp_buf_t disp_buf_2;
|
||||
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
|
||||
lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
|
||||
bool firstTouch = true;
|
||||
static constexpr uint8_t nbWriteLines = 4;
|
||||
static constexpr uint16_t totalNbLines = 320;
|
||||
static constexpr uint16_t visibleNbLines = 240;
|
||||
static constexpr uint8_t MaxScrollOffset() {
|
||||
return LV_VER_RES_MAX - nbWriteLines;
|
||||
}
|
||||
FullRefreshDirections scrollDirection = FullRefreshDirections::None;
|
||||
uint16_t writeOffset = 0;
|
||||
uint16_t scrollOffset = 0;
|
||||
|
||||
lv_disp_drv_t disp_drv;
|
||||
lv_point_t previousClick;
|
||||
|
||||
bool firstTouch = true;
|
||||
static constexpr uint8_t nbWriteLines = 4;
|
||||
static constexpr uint16_t totalNbLines = 320;
|
||||
static constexpr uint16_t visibleNbLines = 240;
|
||||
static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; }
|
||||
FullRefreshDirections scrollDirection = FullRefreshDirections::None;
|
||||
uint16_t writeOffset = 0;
|
||||
uint16_t scrollOffset = 0;
|
||||
|
||||
uint16_t tap_x = 0;
|
||||
uint16_t tap_y = 0;
|
||||
bool tapped = false;
|
||||
uint16_t tap_x = 0;
|
||||
uint16_t tap_y = 0;
|
||||
bool tapped = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,17 @@ namespace Pinetime {
|
||||
namespace Applications {
|
||||
namespace Display {
|
||||
enum class Messages : uint8_t {
|
||||
GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, ButtonPushed,
|
||||
NewNotification, BleFirmwareUpdateStarted, UpdateTimeOut
|
||||
GoToSleep,
|
||||
GoToRunning,
|
||||
UpdateDateTime,
|
||||
UpdateBleConnection,
|
||||
UpdateBatteryLevel,
|
||||
TouchEvent,
|
||||
ButtonPushed,
|
||||
NewNotification,
|
||||
TimerDone,
|
||||
BleFirmwareUpdateStarted,
|
||||
UpdateTimeOut
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,6 @@
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
|
||||
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap};
|
||||
enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap };
|
||||
}
|
||||
}
|
44
src/displayapp/fonts/README.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Fonts
|
||||
|
||||
* [Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)
|
||||
* [Awesome font from LVGL](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff)
|
||||
|
||||
## Generate the fonts:
|
||||
|
||||
* Open the [LVGL font converter](https://lvgl.io/tools/fontconverter)
|
||||
* Name : jetbrains_mono_bold_20
|
||||
* Size : 20
|
||||
* Bpp : 1 bit-per-pixel
|
||||
* Do not enable font compression and horizontal subpixel hinting
|
||||
* Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
||||
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following
|
||||
range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252`
|
||||
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
|
||||
|
||||
Add new symbols:
|
||||
|
||||
* Browse the [cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and find your new symbols
|
||||
* For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list (Remember to keep this
|
||||
readme updated with newest range list)
|
||||
* Convert this hex value into a UTF-8 code
|
||||
using [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f185&mode=hex)
|
||||
* Define the new symbols in `src/displayapp/screens/Symbols.h`:
|
||||
|
||||
```
|
||||
static constexpr const char* newSymbol = "\xEF\x86\x85";
|
||||
```
|
||||
|
||||
#### Navigation font
|
||||
|
||||
To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app)
|
||||
this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and creat a ttf file the
|
||||
project for the site is *lv_font_navi_80.json* you can import it to add or remove icons
|
||||
|
||||
You can also use the online LVGL tool to create the .c
|
||||
|
||||
ttf file : navigation.ttf name : lv_font_navi_80 size : 80px Bpp : 2 bit-per-pixel range : 0xe900-0xe929
|
||||
|
||||
$lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 --no-prefilter -o
|
||||
lv_font_navi_80.c
|
||||
|
||||
#### I use the method above to create the other ttf
|
@ -1,41 +0,0 @@
|
||||
#Fonts
|
||||
* [Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)
|
||||
* [Awesome font from LVGL](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff)
|
||||
|
||||
## Generate the fonts:
|
||||
|
||||
* Open the [LVGL font converter](https://lvgl.io/tools/fontconverter)
|
||||
* Name : jetbrains_mono_bold_20
|
||||
* Size : 20
|
||||
* Bpp : 1 bit-per-pixel
|
||||
* Do not enable font compression and horizontal subpixel hinting
|
||||
* Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
||||
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024`
|
||||
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
|
||||
|
||||
Add new symbols:
|
||||
* Browse the [cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and find your new symbols
|
||||
* For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list (Remember to keep this readme updated with newest range list)
|
||||
* Convert this hex value into a UTF-8 code using [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f185&mode=hex)
|
||||
* Define the new symbols in `src/DisplayApp/Screens/Symbols.h`:
|
||||
```
|
||||
static constex char* newSymbol = "\xEF\x86\x85";
|
||||
```
|
||||
|
||||
#### Navigation font
|
||||
|
||||
To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app)
|
||||
this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and creat a ttf file
|
||||
the project for the site is *lv_font_navi_80.json* you can import it to add or remove icons
|
||||
|
||||
You can also use the online LVGL tool to create the .c
|
||||
|
||||
ttf file : navigation.ttf
|
||||
name : lv_font_navi_80
|
||||
size : 80px
|
||||
Bpp : 2 bit-per-pixel
|
||||
range : 0xe900-0xe929
|
||||
|
||||
$lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 --no-prefilter -o lv_font_navi_80.c
|
||||
|
||||
#### I use the method above to create the other ttf
|
258
src/displayapp/fonts/jetbrains_mono_42.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*******************************************************************************
|
||||
* Size: 42 px
|
||||
* Bpp: 1
|
||||
* Opts:
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
#include "lvgl.h"
|
||||
#else
|
||||
#include "lvgl/lvgl.h"
|
||||
#endif
|
||||
|
||||
#ifndef JETBRAINS_MONO_42
|
||||
#define JETBRAINS_MONO_42 1
|
||||
#endif
|
||||
|
||||
#if JETBRAINS_MONO_42
|
||||
|
||||
/*-----------------
|
||||
* BITMAPS
|
||||
*----------------*/
|
||||
|
||||
/*Store the image of the glyphs*/
|
||||
static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
/* U+0025 "%" */
|
||||
0x1f, 0x80, 0x7, 0x3f, 0xc0, 0xe, 0x7f, 0xe0,
|
||||
0x1c, 0xf0, 0xf0, 0x1c, 0xe0, 0x70, 0x38, 0xe0,
|
||||
0x70, 0x70, 0xe0, 0x70, 0x70, 0xe0, 0x70, 0xe0,
|
||||
0xe0, 0x71, 0xc0, 0xe0, 0x71, 0xc0, 0xf0, 0xf3,
|
||||
0x80, 0x7f, 0xe7, 0x0, 0x3f, 0xc7, 0x0, 0x1f,
|
||||
0x8e, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x3c, 0x0,
|
||||
0x0, 0x38, 0x0, 0x0, 0x71, 0xf8, 0x0, 0xe3,
|
||||
0xfc, 0x0, 0xe7, 0xfe, 0x1, 0xcf, 0xf, 0x3,
|
||||
0x8e, 0x7, 0x3, 0x8e, 0x7, 0x7, 0xe, 0x7,
|
||||
0xe, 0xe, 0x7, 0xe, 0xe, 0x7, 0x1c, 0xe,
|
||||
0x7, 0x38, 0xf, 0xf, 0x38, 0x7, 0xfe, 0x70,
|
||||
0x3, 0xfc, 0xe0, 0x1, 0xf8,
|
||||
|
||||
/* U+0030 "0" */
|
||||
0x3, 0xf8, 0x1, 0xff, 0xc0, 0xff, 0xfe, 0x1f,
|
||||
0x7, 0xc7, 0xc0, 0x7c, 0xf0, 0x7, 0xbc, 0x0,
|
||||
0x7f, 0x80, 0xf, 0xf0, 0x1, 0xfe, 0x0, 0x3f,
|
||||
0xc0, 0x7, 0xf8, 0x0, 0xff, 0xe, 0x1f, 0xe3,
|
||||
0xe3, 0xfc, 0x7c, 0x7f, 0x8f, 0x8f, 0xf0, 0xe1,
|
||||
0xfe, 0x0, 0x3f, 0xc0, 0x7, 0xf8, 0x0, 0xff,
|
||||
0x0, 0x1f, 0xe0, 0x3, 0xfc, 0x0, 0x7f, 0x80,
|
||||
0xf, 0xf0, 0x1, 0xef, 0x0, 0x79, 0xf0, 0x1f,
|
||||
0x1f, 0x7, 0xc3, 0xff, 0xf8, 0x1f, 0xfc, 0x0,
|
||||
0xfe, 0x0,
|
||||
|
||||
/* U+0031 "1" */
|
||||
0x3, 0xf0, 0x0, 0xfe, 0x0, 0x3f, 0xc0, 0x1f,
|
||||
0xf8, 0x7, 0xcf, 0x1, 0xf1, 0xe0, 0x3c, 0x3c,
|
||||
0x7, 0x7, 0x80, 0x80, 0xf0, 0x0, 0x1e, 0x0,
|
||||
0x3, 0xc0, 0x0, 0x78, 0x0, 0xf, 0x0, 0x1,
|
||||
0xe0, 0x0, 0x3c, 0x0, 0x7, 0x80, 0x0, 0xf0,
|
||||
0x0, 0x1e, 0x0, 0x3, 0xc0, 0x0, 0x78, 0x0,
|
||||
0xf, 0x0, 0x1, 0xe0, 0x0, 0x3c, 0x0, 0x7,
|
||||
0x80, 0x0, 0xf0, 0x0, 0x1e, 0x0, 0x3, 0xc0,
|
||||
0x0, 0x78, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf8,
|
||||
|
||||
/* U+0032 "2" */
|
||||
0x3, 0xf8, 0x1, 0xff, 0xc0, 0x7f, 0xfe, 0x1f,
|
||||
0x7, 0xc7, 0xc0, 0x3c, 0xf0, 0x7, 0xbc, 0x0,
|
||||
0x7f, 0x80, 0xf, 0xf0, 0x1, 0xe0, 0x0, 0x3c,
|
||||
0x0, 0x7, 0x80, 0x1, 0xf0, 0x0, 0x3c, 0x0,
|
||||
0xf, 0x80, 0x1, 0xe0, 0x0, 0x7c, 0x0, 0x1f,
|
||||
0x0, 0x7, 0xc0, 0x1, 0xf0, 0x0, 0x7e, 0x0,
|
||||
0xf, 0x80, 0x3, 0xe0, 0x0, 0xf8, 0x0, 0x3e,
|
||||
0x0, 0xf, 0x80, 0x3, 0xe0, 0x0, 0xf8, 0x0,
|
||||
0x3e, 0x0, 0x7, 0xff, 0xfe, 0xff, 0xff, 0xdf,
|
||||
0xff, 0xf8,
|
||||
|
||||
/* U+0033 "3" */
|
||||
0x7f, 0xff, 0x8f, 0xff, 0xf1, 0xff, 0xfe, 0x0,
|
||||
0x3, 0xc0, 0x0, 0xf0, 0x0, 0x3c, 0x0, 0xf,
|
||||
0x0, 0x3, 0xc0, 0x0, 0xf0, 0x0, 0x3e, 0x0,
|
||||
0x7, 0x80, 0x1, 0xfe, 0x0, 0x3f, 0xf0, 0x7,
|
||||
0xff, 0x0, 0x3, 0xf0, 0x0, 0x1e, 0x0, 0x3,
|
||||
0xc0, 0x0, 0x3c, 0x0, 0x7, 0x80, 0x0, 0xf0,
|
||||
0x0, 0x1e, 0x0, 0x3, 0xfc, 0x0, 0x7f, 0x80,
|
||||
0xf, 0xf0, 0x1, 0xef, 0x0, 0x79, 0xf0, 0x1f,
|
||||
0x1f, 0x7, 0xc3, 0xff, 0xf0, 0x1f, 0xfc, 0x0,
|
||||
0xfe, 0x0,
|
||||
|
||||
/* U+0034 "4" */
|
||||
0x0, 0x1e, 0x0, 0xf, 0x80, 0x3, 0xc0, 0x1,
|
||||
0xe0, 0x0, 0x78, 0x0, 0x3c, 0x0, 0x1f, 0x0,
|
||||
0x7, 0x80, 0x3, 0xc0, 0x1, 0xf0, 0x0, 0x78,
|
||||
0x0, 0x3e, 0x0, 0xf, 0x0, 0x7, 0x80, 0xf3,
|
||||
0xe0, 0x3c, 0xf0, 0xf, 0x7c, 0x3, 0xde, 0x0,
|
||||
0xff, 0x0, 0x3f, 0xc0, 0xf, 0xf0, 0x3, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x3,
|
||||
0xc0, 0x0, 0xf0, 0x0, 0x3c, 0x0, 0xf, 0x0,
|
||||
0x3, 0xc0, 0x0, 0xf0, 0x0, 0x3c,
|
||||
|
||||
/* U+0035 "5" */
|
||||
0x7f, 0xff, 0x9f, 0xff, 0xe7, 0xff, 0xf9, 0xe0,
|
||||
0x0, 0x78, 0x0, 0x1e, 0x0, 0x7, 0x80, 0x1,
|
||||
0xe0, 0x0, 0x78, 0x0, 0x1e, 0x0, 0x7, 0x8f,
|
||||
0x81, 0xef, 0xf8, 0x7f, 0xff, 0x1f, 0x87, 0xe7,
|
||||
0xc0, 0x79, 0xe0, 0x1f, 0x0, 0x3, 0xc0, 0x0,
|
||||
0xf0, 0x0, 0x3c, 0x0, 0xf, 0x0, 0x3, 0xc0,
|
||||
0x0, 0xf0, 0x0, 0x3c, 0x0, 0xf, 0xf0, 0x3,
|
||||
0xde, 0x1, 0xe7, 0x80, 0x78, 0xf8, 0x7e, 0x3f,
|
||||
0xff, 0x3, 0xff, 0x80, 0x3f, 0x0,
|
||||
|
||||
/* U+0036 "6" */
|
||||
0x0, 0x3c, 0x0, 0x7, 0x80, 0x0, 0x78, 0x0,
|
||||
0xf, 0x0, 0x1, 0xe0, 0x0, 0x1e, 0x0, 0x3,
|
||||
0xc0, 0x0, 0x3c, 0x0, 0x7, 0x80, 0x0, 0x70,
|
||||
0x0, 0xf, 0x0, 0x1, 0xe7, 0xc0, 0x1f, 0xff,
|
||||
0x3, 0xff, 0xfc, 0x3f, 0xf, 0xc7, 0xc0, 0x3e,
|
||||
0x78, 0x1, 0xe7, 0x80, 0x1f, 0xf0, 0x0, 0xff,
|
||||
0x0, 0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0,
|
||||
0x0, 0xff, 0x0, 0xf, 0xf8, 0x1, 0xe7, 0x80,
|
||||
0x1e, 0x7c, 0x3, 0xe3, 0xf0, 0xfc, 0x1f, 0xff,
|
||||
0x80, 0xff, 0xf0, 0x1, 0xf8, 0x0,
|
||||
|
||||
/* U+0037 "7" */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x0, 0x1e, 0xf0, 0x1, 0xef, 0x0, 0x1e, 0xf0,
|
||||
0x3, 0xcf, 0x0, 0x3c, 0x0, 0x3, 0x80, 0x0,
|
||||
0x78, 0x0, 0x7, 0x80, 0x0, 0xf0, 0x0, 0xf,
|
||||
0x0, 0x0, 0xf0, 0x0, 0x1e, 0x0, 0x1, 0xe0,
|
||||
0x0, 0x3c, 0x0, 0x3, 0xc0, 0x0, 0x3c, 0x0,
|
||||
0x7, 0x80, 0x0, 0x78, 0x0, 0x7, 0x80, 0x0,
|
||||
0xf0, 0x0, 0xf, 0x0, 0x1, 0xe0, 0x0, 0x1e,
|
||||
0x0, 0x1, 0xe0, 0x0, 0x3c, 0x0, 0x3, 0xc0,
|
||||
0x0, 0x7c, 0x0, 0x7, 0x80, 0x0,
|
||||
|
||||
/* U+0038 "8" */
|
||||
0x1, 0xf8, 0x0, 0xff, 0xf0, 0x1f, 0xff, 0x83,
|
||||
0xf0, 0xfc, 0x3c, 0x3, 0xc7, 0xc0, 0x3e, 0x78,
|
||||
0x1, 0xe7, 0x80, 0x1e, 0x78, 0x1, 0xe7, 0x80,
|
||||
0x1e, 0x3c, 0x3, 0xc3, 0xe0, 0x7c, 0x1f, 0xf,
|
||||
0x80, 0xff, 0xf0, 0x3, 0xfc, 0x0, 0x7f, 0xe0,
|
||||
0xf, 0xff, 0x3, 0xe0, 0x7c, 0x3c, 0x3, 0xc7,
|
||||
0x80, 0x1e, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0,
|
||||
0x0, 0xff, 0x0, 0xf, 0xf0, 0x0, 0xff, 0x80,
|
||||
0x1f, 0x7c, 0x3, 0xe7, 0xe0, 0x7e, 0x3f, 0xff,
|
||||
0xc0, 0xff, 0xf0, 0x3, 0xfc, 0x0,
|
||||
|
||||
/* U+0039 "9" */
|
||||
0x3, 0xf8, 0x0, 0xff, 0xf0, 0x1f, 0xff, 0x83,
|
||||
0xe0, 0xfc, 0x7c, 0x3, 0xe7, 0x80, 0x1e, 0xf8,
|
||||
0x1, 0xff, 0x0, 0xf, 0xf0, 0x0, 0xff, 0x0,
|
||||
0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf8, 0x1,
|
||||
0xf7, 0x80, 0x1e, 0x7c, 0x3, 0xe3, 0xe0, 0x7e,
|
||||
0x3f, 0xff, 0xc1, 0xff, 0xfc, 0x7, 0xe7, 0x80,
|
||||
0x0, 0xf8, 0x0, 0xf, 0x0, 0x1, 0xe0, 0x0,
|
||||
0x1e, 0x0, 0x3, 0xc0, 0x0, 0x3c, 0x0, 0x7,
|
||||
0x80, 0x0, 0xf8, 0x0, 0xf, 0x0, 0x1, 0xe0,
|
||||
0x0, 0x1e, 0x0, 0x3, 0xc0, 0x0,
|
||||
|
||||
/* U+003A ":" */
|
||||
0x7d, 0xff, 0xff, 0xff, 0xef, 0x80, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
|
||||
0xf7, 0xff, 0xff, 0xff, 0xbe
|
||||
};
|
||||
|
||||
|
||||
/*---------------------
|
||||
* GLYPH DESCRIPTION
|
||||
*--------------------*/
|
||||
|
||||
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
|
||||
{.bitmap_index = 0, .adv_w = 403, .box_w = 24, .box_h = 31, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 93, .adv_w = 403, .box_w = 19, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 167, .adv_w = 403, .box_w = 19, .box_h = 31, .ofs_x = 4, .ofs_y = 0},
|
||||
{.bitmap_index = 241, .adv_w = 403, .box_w = 19, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 315, .adv_w = 403, .box_w = 19, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 389, .adv_w = 403, .box_w = 18, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 459, .adv_w = 403, .box_w = 18, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 529, .adv_w = 403, .box_w = 20, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 607, .adv_w = 403, .box_w = 20, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 685, .adv_w = 403, .box_w = 20, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 763, .adv_w = 403, .box_w = 20, .box_h = 31, .ofs_x = 3, .ofs_y = 0},
|
||||
{.bitmap_index = 841, .adv_w = 403, .box_w = 7, .box_h = 24, .ofs_x = 9, .ofs_y = 0}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
* CHARACTER MAPPING
|
||||
*--------------------*/
|
||||
|
||||
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 37, .range_length = 1, .glyph_id_start = 1,
|
||||
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||
},
|
||||
{
|
||||
.range_start = 48, .range_length = 11, .glyph_id_start = 2,
|
||||
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*--------------------
|
||||
* ALL CUSTOM DATA
|
||||
*--------------------*/
|
||||
|
||||
#if LV_VERSION_CHECK(8, 0, 0)
|
||||
/*Store all the custom data of the font*/
|
||||
static lv_font_fmt_txt_glyph_cache_t cache;
|
||||
static const lv_font_fmt_txt_dsc_t font_dsc = {
|
||||
#else
|
||||
static lv_font_fmt_txt_dsc_t font_dsc = {
|
||||
#endif
|
||||
.glyph_bitmap = glyph_bitmap,
|
||||
.glyph_dsc = glyph_dsc,
|
||||
.cmaps = cmaps,
|
||||
.kern_dsc = NULL,
|
||||
.kern_scale = 0,
|
||||
.cmap_num = 2,
|
||||
.bpp = 1,
|
||||
.kern_classes = 0,
|
||||
.bitmap_format = 0,
|
||||
#if LV_VERSION_CHECK(8, 0, 0)
|
||||
.cache = &cache
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*-----------------
|
||||
* PUBLIC FONT
|
||||
*----------------*/
|
||||
|
||||
/*Initialize a public general font descriptor*/
|
||||
#if LV_VERSION_CHECK(8, 0, 0)
|
||||
const lv_font_t jetbrains_mono_42 = {
|
||||
#else
|
||||
lv_font_t jetbrains_mono_42 = {
|
||||
#endif
|
||||
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
|
||||
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
|
||||
.line_height = 31, /*The maximum line height required by the font*/
|
||||
.base_line = 0, /*Baseline measured from the bottom of the line*/
|
||||
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
|
||||
.subpx = LV_FONT_SUBPX_NONE,
|
||||
#endif
|
||||
#if LV_VERSION_CHECK(7, 4, 0)
|
||||
.underline_position = -7,
|
||||
.underline_thickness = 2,
|
||||
#endif
|
||||
.dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /*#if JETBRAINS_MONO_42*/
|
||||
|
@ -900,6 +900,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
|
||||
0x7, 0xe0, 0x0, 0x7, 0xf0, 0x0, 0x3, 0xff,
|
||||
0xff, 0xff, 0xcf, 0xff, 0xff, 0xe0,
|
||||
|
||||
/* U+F252 "" */
|
||||
0xff, 0xff, 0xff, 0xfd, 0x80, 0x33, 0x80, 0xe7,
|
||||
0xff, 0xc7, 0xff, 0xf, 0xfe, 0xf, 0xf8, 0xf,
|
||||
0xe0, 0xf, 0x80, 0x7f, 0xc0, 0xe3, 0x83, 0x83,
|
||||
0x86, 0x3, 0x1f, 0xff, 0x3f, 0xfe, 0x7f, 0xfd,
|
||||
0xff, 0xff, 0xff, 0xf8,
|
||||
|
||||
/* U+F293 "" */
|
||||
0x7, 0xe0, 0x3f, 0xe0, 0xfb, 0xe3, 0xf3, 0xe7,
|
||||
0xe3, 0xdf, 0xd3, 0xf9, 0xb3, 0xf9, 0x4f, 0xf8,
|
||||
@ -1184,17 +1191,18 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 3380, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3418, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3456, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 3494, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 3532, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3561, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 3599, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3665, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 3714, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3764, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3824, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3877, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3932, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3985, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0}
|
||||
{.bitmap_index = 3494, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3530, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 3568, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3597, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 3635, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3701, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 3750, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3800, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3860, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 3913, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 3968, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 4021, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@ -1205,8 +1213,8 @@ static const uint16_t unicode_list_2[] = {
|
||||
0x0, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39, 0x47,
|
||||
0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x94, 0x128, 0x184,
|
||||
0x1e5, 0x1fb, 0x21d, 0x23f, 0x240, 0x241, 0x242, 0x243,
|
||||
0x292, 0x293, 0x2f1, 0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f,
|
||||
0x59e, 0x59f, 0x6a8
|
||||
0x251, 0x292, 0x293, 0x2f1, 0x3dc, 0x3fc, 0x45c, 0x54a,
|
||||
0x55f, 0x59e, 0x59f, 0x6a8
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@ -1222,7 +1230,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
},
|
||||
{
|
||||
.range_start = 61441, .range_length = 1705, .glyph_id_start = 160,
|
||||
.unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 35, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 36, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
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);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -67,244 +67,240 @@ static bool inited;
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void style_init_reset(lv_style_t * style)
|
||||
{
|
||||
if(inited) lv_style_reset(style);
|
||||
else lv_style_init(style);
|
||||
static void style_init_reset(lv_style_t* style) {
|
||||
if (inited)
|
||||
lv_style_reset(style);
|
||||
else
|
||||
lv_style_init(style);
|
||||
}
|
||||
|
||||
static void basic_init(void) {
|
||||
|
||||
static void basic_init(void)
|
||||
{
|
||||
style_init_reset(&style_pad);
|
||||
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
|
||||
lv_style_set_pad_bottom(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
|
||||
lv_style_set_pad_left(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
|
||||
lv_style_set_pad_right(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
|
||||
|
||||
style_init_reset(&style_pad);
|
||||
lv_style_set_pad_top(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
|
||||
lv_style_set_pad_bottom(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 30);
|
||||
lv_style_set_pad_left(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
|
||||
lv_style_set_pad_right(&style_pad, LV_STATE_DEFAULT, LV_VER_RES / 40);
|
||||
style_init_reset(&style_circle);
|
||||
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
|
||||
style_init_reset(&style_circle);
|
||||
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
style_init_reset(&style_bg);
|
||||
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal);
|
||||
|
||||
style_init_reset(&style_bg);
|
||||
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal);
|
||||
style_init_reset(&style_box);
|
||||
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
|
||||
|
||||
style_init_reset(&style_box);
|
||||
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
|
||||
style_init_reset(&style_box_border);
|
||||
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
|
||||
style_init_reset(&style_box_border);
|
||||
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
style_init_reset(&style_title);
|
||||
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||
|
||||
style_init_reset(&style_label_white);
|
||||
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
|
||||
style_init_reset(&style_title);
|
||||
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||
style_init_reset(&style_btn);
|
||||
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0x2F3540));
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, LV_COLOR_GREEN);
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x2F3540));
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED | LV_STATE_CHECKED, lv_color_hex3(0x888));
|
||||
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
|
||||
lv_style_set_border_opa(&style_btn, LV_STATE_CHECKED, LV_OPA_TRANSP);
|
||||
|
||||
style_init_reset(&style_label_white);
|
||||
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
||||
|
||||
style_init_reset(&style_btn);
|
||||
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0x2F3540));
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, LV_COLOR_GREEN);
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x2F3540));
|
||||
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED | LV_STATE_CHECKED, lv_color_hex3(0x888));
|
||||
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
|
||||
lv_style_set_border_opa(&style_btn, LV_STATE_CHECKED, LV_OPA_TRANSP);
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
||||
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
||||
lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15));
|
||||
lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2));
|
||||
lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0);
|
||||
lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0);
|
||||
lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0);
|
||||
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
|
||||
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
||||
style_init_reset(&style_btn_border);
|
||||
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_border_width(&style_btn_border, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_bg_opa(&style_btn_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_style_set_bg_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_value_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_transition_prop_3(&style_btn_border, LV_STATE_DEFAULT, LV_STYLE_BG_OPA);
|
||||
|
||||
lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15));
|
||||
lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2));
|
||||
lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0);
|
||||
lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0);
|
||||
lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0);
|
||||
style_init_reset(&style_icon);
|
||||
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
|
||||
style_init_reset(&style_btn_border);
|
||||
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_border_width(&style_btn_border, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_bg_opa(&style_btn_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_style_set_bg_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_value_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_transition_prop_3(&style_btn_border, LV_STATE_DEFAULT, LV_STYLE_BG_OPA);
|
||||
style_init_reset(&style_back);
|
||||
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
|
||||
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||
|
||||
style_init_reset(&style_icon);
|
||||
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
style_init_reset(&style_bar_indic);
|
||||
lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10);
|
||||
|
||||
style_init_reset(&style_back);
|
||||
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
|
||||
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
|
||||
style_init_reset(&style_scrollbar);
|
||||
lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
||||
lv_style_set_size(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 80);
|
||||
lv_style_set_pad_right(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 60);
|
||||
|
||||
style_init_reset(&style_bar_indic);
|
||||
lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_bar_indic, LV_STATE_DEFAULT, 10);
|
||||
style_init_reset(&style_list_btn);
|
||||
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_GRAY);
|
||||
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_darken(LV_PINETIME_GRAY, LV_OPA_20));
|
||||
lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
|
||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
|
||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
|
||||
lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
|
||||
lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
|
||||
lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
|
||||
lv_style_set_pad_bottom(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
|
||||
lv_style_set_pad_inner(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 50);
|
||||
|
||||
style_init_reset(&style_scrollbar);
|
||||
lv_style_set_bg_opa(&style_scrollbar, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_scrollbar, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_bg_color(&style_scrollbar, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
||||
lv_style_set_size(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 80);
|
||||
lv_style_set_pad_right(&style_scrollbar, LV_STATE_DEFAULT, LV_HOR_RES / 60);
|
||||
style_init_reset(&style_ddlist_list);
|
||||
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
|
||||
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
|
||||
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
|
||||
style_init_reset(&style_list_btn);
|
||||
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_GRAY);
|
||||
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_darken(LV_PINETIME_GRAY, LV_OPA_20));
|
||||
lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
|
||||
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
|
||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
|
||||
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
|
||||
lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
|
||||
lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
|
||||
lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
|
||||
lv_style_set_pad_bottom(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
|
||||
lv_style_set_pad_inner(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 50);
|
||||
style_init_reset(&style_ddlist_selected);
|
||||
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
|
||||
style_init_reset(&style_ddlist_list);
|
||||
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
|
||||
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
|
||||
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
style_init_reset(&style_sw_bg);
|
||||
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
||||
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_value_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
|
||||
style_init_reset(&style_ddlist_selected);
|
||||
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
style_init_reset(&style_sw_indic);
|
||||
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN);
|
||||
|
||||
style_init_reset(&style_sw_bg);
|
||||
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
||||
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_value_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
style_init_reset(&style_sw_knob);
|
||||
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, -4);
|
||||
lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, -4);
|
||||
lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, -4);
|
||||
lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, -4);
|
||||
|
||||
style_init_reset(&style_sw_indic);
|
||||
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN);
|
||||
style_init_reset(&style_slider_knob);
|
||||
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6);
|
||||
lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
|
||||
style_init_reset(&style_sw_knob);
|
||||
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, - 4);
|
||||
style_init_reset(&style_arc_indic);
|
||||
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
|
||||
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
|
||||
|
||||
style_init_reset(&style_slider_knob);
|
||||
lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6);
|
||||
lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10);
|
||||
lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14);
|
||||
style_init_reset(&style_arc_bg);
|
||||
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
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);
|
||||
|
||||
style_init_reset(&style_arc_indic);
|
||||
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
|
||||
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
|
||||
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
|
||||
style_init_reset(&style_table_cell);
|
||||
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
|
||||
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
|
||||
lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5);
|
||||
lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5);
|
||||
lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2);
|
||||
|
||||
style_init_reset(&style_arc_bg);
|
||||
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
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);
|
||||
style_init_reset(&style_pad_small);
|
||||
lv_style_int_t pad_small_value = 10;
|
||||
lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
|
||||
style_init_reset(&style_table_cell);
|
||||
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
|
||||
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
|
||||
lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5);
|
||||
lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5);
|
||||
lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2);
|
||||
lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2);
|
||||
style_init_reset(&style_bg_grad);
|
||||
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
|
||||
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
|
||||
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
|
||||
|
||||
style_init_reset(&style_pad_small);
|
||||
lv_style_int_t pad_small_value = 10;
|
||||
lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
|
||||
style_init_reset(&style_lmeter);
|
||||
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30));
|
||||
lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25));
|
||||
|
||||
style_init_reset(&style_bg_grad);
|
||||
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
|
||||
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
|
||||
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
|
||||
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
|
||||
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
|
||||
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
|
||||
|
||||
style_init_reset(&style_lmeter);
|
||||
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_right(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_top(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30));
|
||||
lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25));
|
||||
style_init_reset(&style_chart_serie);
|
||||
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
|
||||
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
|
||||
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
|
||||
|
||||
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
|
||||
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
|
||||
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
|
||||
|
||||
style_init_reset(&style_chart_serie);
|
||||
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
|
||||
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
|
||||
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
|
||||
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
|
||||
|
||||
lv_style_reset(&style_cb_bg);
|
||||
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
|
||||
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
|
||||
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2));
|
||||
lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0);
|
||||
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
|
||||
|
||||
lv_style_reset(&style_cb_bullet);
|
||||
lv_style_set_outline_opa(&style_cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP);
|
||||
lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4));
|
||||
lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
||||
lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_reset(&style_cb_bg);
|
||||
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
|
||||
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
|
||||
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, theme.color_primary);
|
||||
lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2));
|
||||
lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20));
|
||||
lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0);
|
||||
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
|
||||
|
||||
lv_style_reset(&style_cb_bullet);
|
||||
lv_style_set_outline_opa(&style_cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP);
|
||||
lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4));
|
||||
lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE);
|
||||
lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
@ -320,221 +316,216 @@ static void basic_init(void)
|
||||
* @param font_title pointer to a extra large font
|
||||
* @return a pointer to reference this theme later
|
||||
*/
|
||||
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags,
|
||||
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
|
||||
const lv_font_t * font_title)
|
||||
{
|
||||
theme.color_primary = color_primary;
|
||||
theme.color_secondary = color_secondary;
|
||||
theme.font_small = font_small;
|
||||
theme.font_normal = font_normal;
|
||||
theme.font_subtitle = font_subtitle;
|
||||
theme.font_title = font_title;
|
||||
theme.flags = flags;
|
||||
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||
lv_color_t color_secondary,
|
||||
uint32_t flags,
|
||||
const lv_font_t* font_small,
|
||||
const lv_font_t* font_normal,
|
||||
const lv_font_t* font_subtitle,
|
||||
const lv_font_t* font_title) {
|
||||
theme.color_primary = color_primary;
|
||||
theme.color_secondary = color_secondary;
|
||||
theme.font_small = font_small;
|
||||
theme.font_normal = font_normal;
|
||||
theme.font_subtitle = font_subtitle;
|
||||
theme.font_title = font_title;
|
||||
theme.flags = flags;
|
||||
|
||||
basic_init();
|
||||
basic_init();
|
||||
|
||||
theme.apply_xcb = theme_apply;
|
||||
theme.apply_xcb = theme_apply;
|
||||
|
||||
inited = true;
|
||||
inited = true;
|
||||
|
||||
return &theme;
|
||||
return &theme;
|
||||
}
|
||||
|
||||
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
||||
lv_style_list_t* list;
|
||||
|
||||
static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
||||
{
|
||||
lv_style_list_t * list;
|
||||
/*To avoid warnings*/
|
||||
uint32_t name_int = (uint32_t) name;
|
||||
switch (name_int) {
|
||||
case LV_THEME_NONE:
|
||||
break;
|
||||
|
||||
/*To avoid warnings*/
|
||||
uint32_t name_int = (uint32_t) name;
|
||||
switch(name_int) {
|
||||
case LV_THEME_NONE:
|
||||
break;
|
||||
case LV_THEME_SCR:
|
||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
break;
|
||||
|
||||
case LV_THEME_SCR:
|
||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
break;
|
||||
case LV_THEME_OBJ:
|
||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
break;
|
||||
|
||||
case LV_THEME_OBJ:
|
||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
break;
|
||||
case LV_THEME_CONT:
|
||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
break;
|
||||
|
||||
case LV_THEME_CONT:
|
||||
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_CONT_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
break;
|
||||
case LV_THEME_BTN:
|
||||
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
//_lv_style_list_add_style(list, &style_bg_grad);
|
||||
break;
|
||||
|
||||
case LV_THEME_BTN:
|
||||
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
//_lv_style_list_add_style(list, &style_bg_grad);
|
||||
break;
|
||||
case LV_THEME_BTNMATRIX:
|
||||
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
_lv_style_list_add_style(list, &style_pad_small);
|
||||
|
||||
case LV_THEME_BTNMATRIX:
|
||||
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
_lv_style_list_add_style(list, &style_pad_small);
|
||||
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
//_lv_style_list_add_style(list, &style_bg_grad);
|
||||
//_lv_style_list_add_style(list, &style_bg_click);
|
||||
break;
|
||||
|
||||
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
//_lv_style_list_add_style(list, &style_bg_grad);
|
||||
//_lv_style_list_add_style(list, &style_bg_click);
|
||||
break;
|
||||
case LV_THEME_BAR:
|
||||
lv_obj_clean_style_list(obj, LV_BAR_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_BAR_PART_BG);
|
||||
|
||||
case LV_THEME_BAR:
|
||||
lv_obj_clean_style_list(obj, LV_BAR_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_BAR_PART_BG);
|
||||
lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_bar_indic);
|
||||
break;
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_BAR_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_BAR_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_bar_indic);
|
||||
break;
|
||||
case LV_THEME_IMAGE:
|
||||
lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_icon);
|
||||
break;
|
||||
|
||||
case LV_THEME_IMAGE:
|
||||
lv_obj_clean_style_list(obj, LV_IMG_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_IMG_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_icon);
|
||||
break;
|
||||
case LV_THEME_LABEL:
|
||||
lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
break;
|
||||
|
||||
case LV_THEME_LABEL:
|
||||
lv_obj_clean_style_list(obj, LV_LABEL_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_LABEL_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
break;
|
||||
case LV_THEME_SLIDER:
|
||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_sw_bg);
|
||||
|
||||
case LV_THEME_SLIDER:
|
||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_sw_bg);
|
||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_INDIC);
|
||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB);
|
||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB);
|
||||
_lv_style_list_add_style(list, &style_slider_knob);
|
||||
break;
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_SLIDER_PART_KNOB);
|
||||
list = lv_obj_get_style_list(obj, LV_SLIDER_PART_KNOB);
|
||||
_lv_style_list_add_style(list, &style_slider_knob);
|
||||
break;
|
||||
case LV_THEME_LIST:
|
||||
lv_obj_clean_style_list(obj, LV_LIST_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
|
||||
case LV_THEME_LIST:
|
||||
lv_obj_clean_style_list(obj, LV_LIST_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLABLE);
|
||||
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR);
|
||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR);
|
||||
_lv_style_list_add_style(list, &style_scrollbar);
|
||||
break;
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_LIST_PART_SCROLLBAR);
|
||||
list = lv_obj_get_style_list(obj, LV_LIST_PART_SCROLLBAR);
|
||||
_lv_style_list_add_style(list, &style_scrollbar);
|
||||
break;
|
||||
case LV_THEME_LIST_BTN:
|
||||
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_list_btn);
|
||||
break;
|
||||
|
||||
case LV_THEME_LIST_BTN:
|
||||
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_list_btn);
|
||||
break;
|
||||
case LV_THEME_ARC:
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_arc_bg);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_arc_indic);
|
||||
break;
|
||||
|
||||
case LV_THEME_ARC:
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_arc_bg);
|
||||
case LV_THEME_SWITCH:
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_sw_bg);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_arc_indic);
|
||||
break;
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_sw_indic);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_KNOB);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB);
|
||||
_lv_style_list_add_style(list, &style_sw_knob);
|
||||
break;
|
||||
|
||||
case LV_THEME_SWITCH:
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_BG);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_sw_bg);
|
||||
case LV_THEME_DROPDOWN:
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
_lv_style_list_add_style(list, &style_pad);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_sw_indic);
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
_lv_style_list_add_style(list, &style_ddlist_list);
|
||||
_lv_style_list_add_style(list, &style_pad);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_SWITCH_PART_KNOB);
|
||||
list = lv_obj_get_style_list(obj, LV_SWITCH_PART_KNOB);
|
||||
_lv_style_list_add_style(list, &style_sw_knob);
|
||||
break;
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
||||
_lv_style_list_add_style(list, &style_ddlist_selected);
|
||||
|
||||
case LV_THEME_DROPDOWN:
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
_lv_style_list_add_style(list, &style_pad);
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
||||
_lv_style_list_add_style(list, &style_scrollbar);
|
||||
break;
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_LIST);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_LIST);
|
||||
_lv_style_list_add_style(list, &style_box);
|
||||
_lv_style_list_add_style(list, &style_ddlist_list);
|
||||
_lv_style_list_add_style(list, &style_pad);
|
||||
case LV_THEME_TABLE:
|
||||
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SELECTED);
|
||||
_lv_style_list_add_style(list, &style_ddlist_selected);
|
||||
int idx = 1; /* start value should be 1, not zero, since cell styles
|
||||
start at 1 due to presence of LV_TABLE_PART_BG=0
|
||||
in the enum (lv_table.h) */
|
||||
/* declaring idx outside loop to work with older compilers */
|
||||
for (; idx <= LV_TABLE_CELL_STYLE_CNT; idx++) {
|
||||
list = lv_obj_get_style_list(obj, idx);
|
||||
_lv_style_list_add_style(list, &style_table_cell);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
}
|
||||
break;
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
||||
list = lv_obj_get_style_list(obj, LV_DROPDOWN_PART_SCROLLBAR);
|
||||
_lv_style_list_add_style(list, &style_scrollbar);
|
||||
break;
|
||||
case LV_THEME_LINEMETER:
|
||||
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
_lv_style_list_add_style(list, &style_lmeter);
|
||||
break;
|
||||
|
||||
case LV_THEME_TABLE:
|
||||
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
case LV_THEME_CHART:
|
||||
lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES);
|
||||
list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
_lv_style_list_add_style(list, &style_chart_serie);
|
||||
break;
|
||||
|
||||
int idx = 1; /* start value should be 1, not zero, since cell styles
|
||||
start at 1 due to presence of LV_TABLE_PART_BG=0
|
||||
in the enum (lv_table.h) */
|
||||
/* declaring idx outside loop to work with older compilers */
|
||||
for(; idx <= LV_TABLE_CELL_STYLE_CNT; idx ++) {
|
||||
list = lv_obj_get_style_list(obj, idx);
|
||||
_lv_style_list_add_style(list, &style_table_cell);
|
||||
_lv_style_list_add_style(list, &style_label_white);
|
||||
}
|
||||
break;
|
||||
case LV_THEME_CHECKBOX:
|
||||
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_cb_bg);
|
||||
|
||||
case LV_THEME_LINEMETER:
|
||||
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &style_bg);
|
||||
_lv_style_list_add_style(list, &style_lmeter);
|
||||
break;
|
||||
|
||||
case LV_THEME_CHART:
|
||||
lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES);
|
||||
list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
_lv_style_list_add_style(list, &style_chart_serie);
|
||||
break;
|
||||
|
||||
case LV_THEME_CHECKBOX:
|
||||
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG);
|
||||
_lv_style_list_add_style(list, &style_cb_bg);
|
||||
|
||||
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
_lv_style_list_add_style(list, &style_cb_bullet);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
|
||||
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BULLET);
|
||||
_lv_style_list_add_style(list, &style_btn);
|
||||
_lv_style_list_add_style(list, &style_cb_bullet);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
@ -19,24 +19,22 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
/*Colors*/
|
||||
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
|
||||
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
|
||||
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
|
||||
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
|
||||
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) //006fb6
|
||||
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
|
||||
#define LV_PINETIME_RED lv_color_hex(0xd51732)
|
||||
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
|
||||
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
|
||||
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
|
||||
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
|
||||
#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) // 006fb6
|
||||
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
|
||||
#define LV_PINETIME_RED lv_color_hex(0xd51732)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the default
|
||||
* @param color_primary the primary color of the theme
|
||||
@ -48,9 +46,13 @@ extern "C" {
|
||||
* @param font_title pointer to a extra large font
|
||||
* @return a pointer to reference this theme later
|
||||
*/
|
||||
lv_theme_t * lv_pinetime_theme_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags,
|
||||
const lv_font_t * font_small, const lv_font_t * font_normal, const lv_font_t * font_subtitle,
|
||||
const lv_font_t * font_title);
|
||||
lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
|
||||
lv_color_t color_secondary,
|
||||
uint32_t flags,
|
||||
const lv_font_t* font_small,
|
||||
const lv_font_t* font_normal,
|
||||
const lv_font_t* font_subtitle,
|
||||
const lv_font_t* font_title);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
@ -8,31 +8,34 @@
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app,
|
||||
Pinetime::Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Controllers::DateTime& dateTimeController) :
|
||||
Screen(app),
|
||||
settingsController{settingsController},
|
||||
batteryController{batteryController},
|
||||
dateTimeController{dateTimeController},
|
||||
screens{app,
|
||||
settingsController.GetAppMenu(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen2(); },
|
||||
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||
},
|
||||
Screens::ScreenListModes::UpDown
|
||||
} {}
|
||||
|
||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Controllers::DateTime& dateTimeController)
|
||||
: Screen(app),
|
||||
settingsController {settingsController},
|
||||
batteryController {batteryController},
|
||||
dateTimeController {dateTimeController},
|
||||
screens {app,
|
||||
settingsController.GetAppMenu(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen1();
|
||||
},
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return CreateScreen2();
|
||||
},
|
||||
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||
},
|
||||
Screens::ScreenListModes::UpDown} {
|
||||
}
|
||||
|
||||
ApplicationList::~ApplicationList() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool ApplicationList::Refresh() {
|
||||
if(running)
|
||||
if (running)
|
||||
running = screens.Refresh();
|
||||
return running;
|
||||
}
|
||||
@ -42,31 +45,27 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
||||
std::array<Screens::Tile::Applications, 6> applications {
|
||||
{
|
||||
{Symbols::stopWatch, Apps::StopWatch},
|
||||
{Symbols::music, Apps::Music},
|
||||
{Symbols::map, Apps::Navigation},
|
||||
{Symbols::shoe, Apps::Motion},
|
||||
{Symbols::heartBeat, Apps::HeartRate},
|
||||
{"", Apps::None},
|
||||
}
|
||||
};
|
||||
std::array<Screens::Tile::Applications, 6> applications {{
|
||||
{Symbols::stopWatch, Apps::StopWatch},
|
||||
{Symbols::music, Apps::Music},
|
||||
{Symbols::map, Apps::Navigation},
|
||||
{Symbols::shoe, Apps::Steps},
|
||||
{Symbols::heartBeat, Apps::HeartRate},
|
||||
{Symbols::hourGlass, Apps::Timer},
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
std::array<Screens::Tile::Applications, 6> applications {
|
||||
{
|
||||
{Symbols::paintbrush, Apps::Paint},
|
||||
{Symbols::paddle, Apps::Paddle},
|
||||
{"2", Apps::Twos},
|
||||
{"", Apps::None},
|
||||
{"", Apps::None},
|
||||
{"", Apps::None},
|
||||
}
|
||||
};
|
||||
std::array<Screens::Tile::Applications, 6> applications {{
|
||||
{Symbols::paintbrush, Apps::Paint},
|
||||
{Symbols::paddle, Apps::Paddle},
|
||||
{"2", Apps::Twos},
|
||||
{"M", Apps::Motion},
|
||||
{"", Apps::None},
|
||||
{"", Apps::None},
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||
}
|
||||
@ -84,4 +83,3 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
|
||||
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
|
||||
}*/
|
||||
|
||||
|
@ -12,24 +12,24 @@ namespace Pinetime {
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
class ApplicationList : public Screen {
|
||||
public:
|
||||
explicit ApplicationList(DisplayApp* app,
|
||||
Pinetime::Controllers::Settings &settingsController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Controllers::DateTime& dateTimeController);
|
||||
~ApplicationList() override;
|
||||
bool Refresh() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
private:
|
||||
public:
|
||||
explicit ApplicationList(DisplayApp* app,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Controllers::DateTime& dateTimeController);
|
||||
~ApplicationList() override;
|
||||
bool Refresh() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
Controllers::Settings& settingsController;
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
Controllers::DateTime& dateTimeController;
|
||||
private:
|
||||
Controllers::Settings& settingsController;
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
Controllers::DateTime& dateTimeController;
|
||||
|
||||
ScreenList<2> screens;
|
||||
std::unique_ptr<Screen> CreateScreen1();
|
||||
std::unique_ptr<Screen> CreateScreen2();
|
||||
//std::unique_ptr<Screen> CreateScreen3();
|
||||
ScreenList<2> screens;
|
||||
std::unique_ptr<Screen> CreateScreen1();
|
||||
std::unique_ptr<Screen> CreateScreen2();
|
||||
// std::unique_ptr<Screen> CreateScreen3();
|
||||
};
|
||||
}
|
||||
}
|
||||
|