summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.devcontainer/Dockerfile2
-rw-r--r--.devcontainer/build.sh2
-rw-r--r--.github/ISSUE_TEMPLATE/bug-report.yaml58
-rw-r--r--.github/ISSUE_TEMPLATE/feature-request.yaml40
-rw-r--r--.github/workflows/main.yml8
-rw-r--r--.gitignore6
-rw-r--r--.vscode/settings.json52
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md9
-rw-r--r--bootloader/README.md4
-rw-r--r--doc/MemoryAnalysis.md18
-rw-r--r--doc/NavigationService.md10
-rw-r--r--doc/ble.md242
-rw-r--r--doc/buildAndProgram.md15
-rw-r--r--doc/buildWithDocker.md10
-rw-r--r--doc/buildWithVScode.md12
-rw-r--r--doc/code/Apps.md106
-rw-r--r--doc/code/Intro.md42
-rw-r--r--doc/contribute.md27
-rw-r--r--doc/filesInReleaseNotes.md4
-rw-r--r--doc/gettingStarted/gettingStarted-1.0.md12
-rw-r--r--doc/gettingStarted/ota-gadgetbridge-nrfconnect.md2
-rwxr-xr-xdocker/build.sh2
-rw-r--r--gcc_nrf52-mcuboot.ld10
-rw-r--r--gcc_nrf52.ld11
-rw-r--r--src/BootErrors.h10
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/components/alarm/AlarmController.cpp114
-rw-r--r--src/components/alarm/AlarmController.h68
-rw-r--r--src/components/battery/BatteryController.cpp29
-rw-r--r--src/components/battery/BatteryController.h9
-rw-r--r--src/components/ble/AlertNotificationClient.cpp14
-rw-r--r--src/components/ble/AlertNotificationService.cpp11
-rw-r--r--src/components/ble/BatteryInformationService.cpp6
-rw-r--r--src/components/ble/CurrentTimeClient.cpp4
-rw-r--r--src/components/ble/CurrentTimeService.cpp4
-rw-r--r--src/components/ble/DeviceInformationService.cpp14
-rw-r--r--src/components/ble/DfuService.cpp26
-rw-r--r--src/components/ble/HeartRateService.cpp4
-rw-r--r--src/components/ble/ImmediateAlertService.cpp6
-rw-r--r--src/components/ble/NavigationService.cpp77
-rw-r--r--src/components/ble/NavigationService.h17
-rw-r--r--src/components/ble/NotificationManager.cpp8
-rw-r--r--src/components/ble/NotificationManager.h5
-rw-r--r--src/components/datetime/DateTimeController.cpp51
-rw-r--r--src/components/datetime/DateTimeController.h17
-rw-r--r--src/components/fs/FS.h2
-rw-r--r--src/components/motor/MotorController.cpp10
-rw-r--r--src/components/motor/MotorController.h5
-rw-r--r--src/components/settings/Settings.h14
-rw-r--r--src/displayapp/Apps.h6
-rw-r--r--src/displayapp/DisplayApp.cpp68
-rw-r--r--src/displayapp/DisplayApp.h11
-rw-r--r--src/displayapp/DisplayAppRecovery.cpp1
-rw-r--r--src/displayapp/DisplayAppRecovery.h4
-rw-r--r--src/displayapp/Messages.h3
-rw-r--r--src/displayapp/screens/Alarm.cpp265
-rw-r--r--src/displayapp/screens/Alarm.h56
-rw-r--r--src/displayapp/screens/ApplicationList.cpp2
-rw-r--r--src/displayapp/screens/BatteryInfo.cpp2
-rw-r--r--src/displayapp/screens/Error.cpp50
-rw-r--r--src/displayapp/screens/Error.h21
-rw-r--r--src/displayapp/screens/FlashLight.cpp114
-rw-r--r--src/displayapp/screens/FlashLight.h16
-rw-r--r--src/displayapp/screens/Metronome.cpp2
-rw-r--r--src/displayapp/screens/Notifications.cpp4
-rw-r--r--src/displayapp/screens/Paddle.cpp4
-rw-r--r--src/displayapp/screens/PineTimeStyle.cpp33
-rw-r--r--src/displayapp/screens/PineTimeStyle.h4
-rw-r--r--src/displayapp/screens/SystemInfo.cpp28
-rw-r--r--src/displayapp/screens/SystemInfo.h4
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.cpp29
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.h2
-rw-r--r--src/displayapp/screens/WatchFaceDigital.cpp12
-rw-r--r--src/displayapp/screens/WatchFaceDigital.h1
-rw-r--r--src/displayapp/screens/settings/QuickSettings.cpp8
-rw-r--r--src/displayapp/screens/settings/SettingSetDate.cpp198
-rw-r--r--src/displayapp/screens/settings/SettingSetDate.h41
-rw-r--r--src/displayapp/screens/settings/SettingSetTime.cpp154
-rw-r--r--src/displayapp/screens/settings/SettingSetTime.h33
-rw-r--r--src/displayapp/screens/settings/Settings.cpp10
-rw-r--r--src/drivers/Cst816s.cpp36
-rw-r--r--src/drivers/Cst816s.h16
-rw-r--r--src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h2
-rw-r--r--src/main.cpp25
-rw-r--r--src/systemtask/Messages.h4
-rw-r--r--src/systemtask/SystemTask.cpp79
-rw-r--r--src/systemtask/SystemTask.h6
88 files changed, 2176 insertions, 417 deletions
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 1dd68f24..46e2facb 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -55,7 +55,7 @@ RUN unzip -q /tmp/nRF5_SDK_15.3.0_59ac345 -d /opt
RUN rm /tmp/nRF5_SDK_15.3.0_59ac345
# McuBoot
# RUN bash -c "source /opt/build.sh; GetMcuBoot;"
-RUN git clone https://github.com/JuulLabs-OSS/mcuboot.git
+RUN git clone https://github.com/mcu-tools/mcuboot.git
RUN pip3 install -r ./mcuboot/scripts/requirements.txt
RUN adduser infinitime
diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh
index 8f0d0fa9..5dcdf91d 100644
--- a/.devcontainer/build.sh
+++ b/.devcontainer/build.sh
@@ -43,7 +43,7 @@ GetGcc() {
}
GetMcuBoot() {
- git clone https://github.com/JuulLabs-OSS/mcuboot.git "$TOOLS_DIR/mcuboot"
+ git clone https://github.com/mcu-tools/mcuboot.git "$TOOLS_DIR/mcuboot"
pip3 install -r "$TOOLS_DIR/mcuboot/scripts/requirements.txt"
}
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml
new file mode 100644
index 00000000..f0fb076e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.yaml
@@ -0,0 +1,58 @@
+name: Bug Report
+description: File a bug report
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Thanks for taking the time to fill out this bug report!**
+ *Please, before opening a bug report, check if similar issues already exist. In that case, use those issues to provide your feedback instead.*
+ - type: checkboxes
+ attributes:
+ options:
+ - label: I searched for similar bug reports and found none was relevant.
+ required: true
+ - type: input
+ id: desc-brief
+ attributes:
+ label: What happened?
+ description: A one-line description of the bug.
+ placeholder: "Ex. I woke up as a Kafkian insect this morning."
+ validations:
+ required: true
+ - type: input
+ id: desc-expected
+ attributes:
+ label: What should happen instead?
+ description: The behaviour you were expecting to see.
+ placeholder: "Ex. I was expecting to wake up as a human."
+ - type: textarea
+ id: desc-steps
+ attributes:
+ label: Reproduction steps
+ description: "How do you trigger this bug? Please walk us through it step by step."
+ validations:
+ required: true
+ - type: textarea
+ id: desc-long
+ attributes:
+ label: More details?
+ description: Give us more details about the bug and any personal attempts you made to fix it.
+ placeholder: Tell us more!
+ - type: input
+ id: version
+ attributes:
+ label: Version
+ description: |
+ What [version of the firmware](https://github.com/JF002/InfiniTime/blob/develop/doc/gettingStarted/gettingStarted-1.0.md#how-to-check-the-version-of-infinitime-and-the-bootloader) are you running?
+ If you are running an older version, please consider [updating to the latest firmware](https://github.com/JF002/InfiniTime/blob/develop/doc/gettingStarted/gettingStarted-1.0.md#how-to-update-your-pinetime).
+ If you are running directly from git, specify the branch or the commit hash directly.
+ placeholder: "Ex. v1.6.0 or develop or fc922b60"
+ validations:
+ required: true
+ - type: input
+ id: companion-app
+ attributes:
+ label: Companion app
+ description: Which companion app are you using (if relevant)?
+ placeholder: "Ex. Gadgetbridge v0.60.0, Siglo v0.9.4"
diff --git a/.github/ISSUE_TEMPLATE/feature-request.yaml b/.github/ISSUE_TEMPLATE/feature-request.yaml
new file mode 100644
index 00000000..26e4fa0f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.yaml
@@ -0,0 +1,40 @@
+name: Feature Request
+description: File a feature request
+labels: ["feature request"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Thanks for taking the time to fill out this feature request!**
+ *Please, before opening a feature request, check if similar issues already exist. In that case, use those issues to provide your feedback instead.*
+ - type: checkboxes
+ attributes:
+ options:
+ - label: I searched for similar feature request and found none was relevant.
+ required: true
+ - type: markdown
+ attributes:
+ value: |
+ **Note:** keep in mind that, while InfiniTime is usable, it is still under heavy development and as such it is continuously evolving.
+ Some features you want to see implemented might not be compatible with the current state of the project, or might not even be suitable to include *in the firmware* of the watch.
+ - type: input
+ id: desc-brief
+ attributes:
+ label: Pitch us your idea!
+ description: A one-line elevator pitch of the feature you'd like to see implemented.
+ placeholder: "Ex. My dog wants InfiniTime on its smart collar."
+ validations:
+ required: true
+ - type: textarea
+ id: desc-long
+ attributes:
+ label: Description
+ description: |
+ Give us a detailed description of the feature you are proposing. Mockups or a description of the possible use cases are highly appreciated.
+ Tell us why this should be included in the firmware.
+ placeholder: "Ex. Here is a drawing of my dog wearing an InfiniTime collar and smiling."
+ - type: markdown
+ id: companion-app
+ attributes:
+ value: |
+ If this requires features missing from other software (for example a companion app), please take care of opening any relevant feature request over there as well.
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index bd24359a..3b753a37 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -153,6 +153,14 @@ jobs:
name: pinetime-app.out
path: build/src/pinetime-app*.out
+ #########################################################################################
+ # Make but don't Upload the Recovery Firmware to be sure it builds correctly
+
+ - name: Make pinetime-recovery
+ run: |
+ cd build
+ make pinetime-recovery
+
#########################################################################################
# Finish
diff --git a/.gitignore b/.gitignore
index 6de76a9e..39fb672b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,4 +38,8 @@ Testing/Temporary/
**/.DS_Store
# Windows
-**/thumbs.db \ No newline at end of file
+**/thumbs.db
+
+#VSCODE
+.vscode/.cortex-debug.registers.state.json
+.vscode/.cortex-debug.peripherals.state.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8f0e63f4..f1cc3a81 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,5 +5,55 @@
"-DNRF5_SDK_PATH=${env:NRF5_SDK_PATH}",
],
"cmake.generator": "Unix Makefiles",
- "clang-tidy.buildPath": "build/compile_commands.json"
+ "clang-tidy.buildPath": "build/compile_commands.json",
+ "files.associations": {
+ "array": "cpp",
+ "atomic": "cpp",
+ "bit": "cpp",
+ "*.tcc": "cpp",
+ "bitset": "cpp",
+ "cctype": "cpp",
+ "chrono": "cpp",
+ "clocale": "cpp",
+ "cmath": "cpp",
+ "cstdarg": "cpp",
+ "cstddef": "cpp",
+ "cstdint": "cpp",
+ "cstdio": "cpp",
+ "cstdlib": "cpp",
+ "ctime": "cpp",
+ "cwchar": "cpp",
+ "cwctype": "cpp",
+ "deque": "cpp",
+ "unordered_map": "cpp",
+ "vector": "cpp",
+ "exception": "cpp",
+ "algorithm": "cpp",
+ "functional": "cpp",
+ "iterator": "cpp",
+ "memory": "cpp",
+ "memory_resource": "cpp",
+ "numeric": "cpp",
+ "optional": "cpp",
+ "random": "cpp",
+ "ratio": "cpp",
+ "string": "cpp",
+ "string_view": "cpp",
+ "system_error": "cpp",
+ "tuple": "cpp",
+ "type_traits": "cpp",
+ "utility": "cpp",
+ "fstream": "cpp",
+ "initializer_list": "cpp",
+ "iosfwd": "cpp",
+ "istream": "cpp",
+ "limits": "cpp",
+ "new": "cpp",
+ "ostream": "cpp",
+ "sstream": "cpp",
+ "stdexcept": "cpp",
+ "streambuf": "cpp",
+ "cinttypes": "cpp",
+ "typeinfo": "cpp"
+ }
}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f2402e57..a8ecb81f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
-project(pinetime VERSION 1.4.0 LANGUAGES C CXX ASM)
+project(pinetime VERSION 1.6.0 LANGUAGES C CXX ASM)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
diff --git a/README.md b/README.md
index 0d5cad93..765aa863 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# InfiniTime
-[![Build PineTime Firmware](https://github.com/JF002/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/JF002/InfiniTime/actions)
+[![Build PineTime Firmware](https://github.com/InfiniTimeOrg/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/InfiniTimeOrg/InfiniTime/actions)
![InfiniTime logo](images/infinitime-logo.jpg "InfiniTime Logo")
@@ -65,14 +65,15 @@ As of now, here is the list of achievements of this project:
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
- * **[Experimental]** [Infini-iOS](https://github.com/xan-m/Infini-iOS) (on iOS)
+ * **[Experimental]** [InfiniLink](https://github.com/xan-m/InfiniLink) (on iOS)
- OTA (Over-the-air) update via BLE
- - [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
+ - [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://www.mcuboot.com)
## Documentation
### Develop
-
+ - [Rough structure of the code](doc/code/Intro.md)
+ - [How to implement an application](doc/code/Apps.md)
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
diff --git a/bootloader/README.md b/bootloader/README.md
index c04e0e34..9f99602b 100644
--- a/bootloader/README.md
+++ b/bootloader/README.md
@@ -1,5 +1,5 @@
# About this bootloader
-The [bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/tree/master/libs/pinetime_boot/src) is mostly developed by [Lup Yuen](https://github.com/lupyuen). It is based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/) and [Mynewt](https://mynewt.apache.org/).
+The [bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/tree/master/libs/pinetime_boot/src) is mostly developed by [Lup Yuen](https://github.com/lupyuen). It is based on [MCUBoot](https://www.mcuboot.com) and [Mynewt](https://mynewt.apache.org/).
The goal of this project is to provide a common bootloader for multiple (all?) Pinetime projects. It allows to upgrade the current bootloader and even replace the current application by another one that supports the same bootloader.
@@ -86,7 +86,7 @@ make pinetime-mcuboot-app
The binary is located in *<build directory>/src/pinetime-mcuboot-app.bin*.
-It must me converted into a MCUBoot image using *imgtool.py* from [MCUBoot](https://github.com/JuulLabs-OSS/mcuboot/tree/master/scripts). Simply checkout the project and run the script <mcuboot root>/scripts/imgtool.py with the following command line:
+It must me converted into a MCUBoot image using *imgtool.py* from [MCUBoot](https://github.com/mcu-tools/mcuboot/tree/master/scripts). Simply checkout the project and run the script <mcuboot root>/scripts/imgtool.py with the following command line:
`
imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header <build directory>/src/pinetime-mcuboot-app.bin image.bin
diff --git a/doc/MemoryAnalysis.md b/doc/MemoryAnalysis.md
index 3251c98d..7304e3f3 100644
--- a/doc/MemoryAnalysis.md
+++ b/doc/MemoryAnalysis.md
@@ -6,7 +6,7 @@ The PineTime is equipped with the following memories:
Note that the NRF52832 cannot execute code stored in the external flash : we need to store the whole firmware in the internal flash memory, and use the external one to store graphicals assets, fonts...
-This document describes how the RAM and Flash memories are used in InfiniTime and how to analyze and monitor their usage. It was written in the context of [this memory analysis effort](https://github.com/JF002/InfiniTime/issues/313).
+This document describes how the RAM and Flash memories are used in InfiniTime and how to analyze and monitor their usage. It was written in the context of [this memory analysis effort](https://github.com/InfiniTimeOrg/InfiniTime/issues/313).
## Code sections
A binary is composed of multiple sections. Most of the time, these sections are : .text, .rodata, .data and .bss but more sections can be defined in the linker script.
@@ -38,7 +38,7 @@ In this analysis, I used [Linkermapviz](https://github.com/PromyLOPh/linkermapvi
Using this tool, you can easily see the size of each symbol relative to the other one, and check what is using most of the space,...
-Also, as Linkermapviz is written in Python, you can easily modify it to adapt it to your firmware, export data in another format,... For example, [I modified it to parse the contents of the MAP file and export it in a CSV file](https://github.com/JF002/InfiniTime/issues/313#issuecomment-842338620). I could later on open this file in LibreOffice Calc and use sort/filter functionality to search for specific symbols in specific files...
+Also, as Linkermapviz is written in Python, you can easily modify it to adapt it to your firmware, export data in another format,... For example, [I modified it to parse the contents of the MAP file and export it in a CSV file](https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620). I could later on open this file in LibreOffice Calc and use sort/filter functionality to search for specific symbols in specific files...
### Puncover
[Puncover](https://github.com/HBehrens/puncover) is another useful tools that analyses the binary file generated by the compiler (the .out file that contains all debug information). It provides valuable information about the symbols (data and code): name, position, size, max stack of each functions, callers, callees...
@@ -69,8 +69,8 @@ This way, you can easily check what needs to be optimized : we should find a way
It's always a good idea to check the flash memory space when working on the project : this way, you can easily check that your developments are using a reasonable amount of space.
### Links
- - Analysis with linkermapviz : https://github.com/JF002/InfiniTime/issues/313#issuecomment-842338620
- - Analysis with Puncover : https://github.com/JF002/InfiniTime/issues/313#issuecomment-847311392
+ - Analysis with linkermapviz : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620
+ - Analysis with Puncover : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-847311392
## RAM
RAM memory contains all the data that can be modified at run-time: variables, stack, heap...
@@ -93,7 +93,7 @@ int main() {
In Infinitime 1.1, the biggest buffers are the buffers allocated for LVGL (14KB) and the one for FreeRTOS (16KB). Nimble also allocated 9KB of RAM.
### Stack
-The stack will be used for everything except tasks, which have their own stack allocated by FreeRTOS. The stack is 8192B and is allocated in the [linker script](https://github.com/JF002/InfiniTime/blob/develop/nrf_common.ld#L148).
+The stack will be used for everything except tasks, which have their own stack allocated by FreeRTOS. The stack is 8192B and is allocated in the [linker script](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/nrf_common.ld#L148).
An easy way to monitor its usage is by filling the section with a known pattern at boot time, then use the firmware and dump the memory. You can then check the maximum stack usage by checking the address from the beginning of the stack that were overwritten.
#### Fill the stack section by a known pattern:
@@ -197,10 +197,10 @@ On the following dump, the maximum stack usage is 520 bytes (0xFFFF - 0xFDF8):
According to my experimentations, we don't use the stack that much, and 8192 bytes is probably way too big for InfiniTime!
#### Links
- - https://github.com/JF002/InfiniTime/issues/313#issuecomment-851035070
+ - https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035070
### Heap
-The heap is declared in the [linker script](https://github.com/JF002/InfiniTime/blob/develop/nrf_common.ld#L136) and its current size is 8192 bytes. The heap is used for dynamic memory allocation(`malloc()`, `new`...).
+The heap is declared in the [linker script](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/nrf_common.ld#L136) and its current size is 8192 bytes. The heap is used for dynamic memory allocation(`malloc()`, `new`...).
Heap monitoring is not easy, but it seems that we can use the following code to know the current usage of the heap:
@@ -239,7 +239,7 @@ Using this technique, I was able to trace all malloc calls at boot (boot -> digi
- hr task = 304
#### Links
- - https://github.com/JF002/InfiniTime/issues/313#issuecomment-851035625
+ - https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-851035625
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-1-calculating-stack-size/
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-2-properly-allocating-stacks/
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-3-avoiding-heap-errors/
@@ -263,7 +263,7 @@ For example a simple lv_label needs **~140 bytes** of memory.
I tried to monitor this max value while going through all the apps of InfiniTime 1.1 : the max value I've seen is **5660 bytes**. It means that we could probably **reduce the size of the buffer from 14KB to 6 - 10 KB** (we have to take the fragmentation of the memory into account).
### Links
- - https://github.com/JF002/InfiniTime/issues/313#issuecomment-850890064
+ - https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-850890064
## FreeRTOS heap and task stack
diff --git a/doc/NavigationService.md b/doc/NavigationService.md
index d0899817..fd81d0bf 100644
--- a/doc/NavigationService.md
+++ b/doc/NavigationService.md
@@ -9,19 +9,19 @@ manDist (string) - Manouvre Distance, the distance to the upcoming change
progress (uint8) - Percent complete of total route, value 0-100
## Service
-The service UUID is c7e60001-78fc-48fe-8e23-433b3a1942d0
+The service UUID is 00010000-78fc-48fe-8e23-433b3a1942d0
## Characteristics
-## Flags (UUID c7e60002-78fc-48fe-8e23-433b3a1942d0)
+## Flags (UUID 00010001-78fc-48fe-8e23-433b3a1942d0)
All included icons are from pure-maps, which provides the actual routing from the client. The icon names ultimately come from the mapbox project "direction-icons", See https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation See the end of this document for the full lsit of supported icon names.
-## Narrative (UUID c7e60003-78fc-48fe-8e23-433b3a1942d0)
+## Narrative (UUID 00010002-78fc-48fe-8e23-433b3a1942d0)
This is a client supplied string describing the upcoming instruction such as "At the roundabout take the first exit".
-## Man Dist (UUID c7e60004-78fc-48fe-8e23-433b3a1942d0)
+## Man Dist (UUID 00010003-78fc-48fe-8e23-433b3a1942d0)
This is a short string describing the distance to the upcoming instruction such as "50 m".
-## Progress (UUID c7e60001=5-78fc-48fe-8e23-433b3a1942d0)
+## Progress (UUID 00010004-78fc-48fe-8e23-433b3a1942d0)
The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
## Full icon list
diff --git a/doc/ble.md b/doc/ble.md
index 518b99c8..2f8ba41c 100644
--- a/doc/ble.md
+++ b/doc/ble.md
@@ -2,23 +2,59 @@
## Introduction
This page describes the BLE implementation and API built in this firmware.
-**Note** : I'm a beginner in BLE related technologies and the information of this document reflect my current knowledge and understanding of the BLE stack. These informations might be erroneous or incomplete. Feel free to submit a PR if you think you can improve these.
+**Note** : I'm a beginner in BLE related technologies and the information in this document reflects my current knowledge and understanding of the BLE stack. This information might be erroneous or incomplete. Feel free to submit a PR if you think you can improve it.
+
+---
+
+### Table of Contents
+
+- [BLE Connection](#ble-connection)
+- [BLE UUIDs](#ble-uuids)
+- [BLE Services](#ble-services)
+ - [CTS](#cts)
+ - [ANS](#ans)
+- [Getting Information](#getting-information)
+ - [Firmware Version](#firmware-version)
+ - [Battery Level](#battery-level)
+ - [Heart Rate](#heart-rate)
+- [Notifications](#notifications)
+ - [New Alert](#new-alert)
+ - [Notification Event](#notification-event)
+- [Firmware Upgrades](#firmware-upgrades)
+ - [Step one](#step-one)
+ - [Step two](#step-two)
+ - [Step three](#step-three)
+ - [Step four](#step-four)
+ - [Step five](#step-five)
+ - [Step six](#step-six)
+ - [Step seven](#step-seven)
+ - [Step eight](#step-eight)
+ - [Step nine](#step-nine)
+- [Music Control](#music-control)
+ - [Events](#events)
+ - [Status](#status)
+ - [Artist, Track, and Album](#artist-track-and-album)
+- [Time](#time)
+
+---
## BLE Connection
-When starting the firmware start a BLE advertising : it sends small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices.
+When starting, the firmware starts BLE advertising. It sends small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices.
-A companion application (running on a PC, RaspberryPi, smartphone) which received this avertising packet can request a connection to the device. This connection procedure allows the 2 devices to negotiate communication parameters, security keys,...
+A companion application (running on a PC, Raspberry Pi, smartphone, etc.) which receives this advertising packet can request a connection to the device. This connection procedure allows the 2 devices to negotiate communication parameters, security keys, etc.
-When the connection is established, the pinetime will try to discover services running on the companion application. For now **CTS** (**C**urrent **T**ime **S**ervice) and **ANS** (**A**lert **N**otification **S**ervice) are supported.
+When the connection is established, the PineTime will try to discover services running on the companion application. For now **CTS** (**C**urrent **T**ime **S**ervice) and **ANS** (**A**lert **N**otification **S**ervice) are supported.
If **CTS** is detected, it'll request the current time to the companion application. If **ANS** is detected, it will listen to new notifications coming from the companion application.
![BLE connection sequence diagram](ble/connection_sequence.png "BLE connection sequence diagram")
+---
+
## BLE UUIDs
When possible, InfiniTime tries to implement BLE services defined by the BLE specification.
-When the service does not exist in the BLE specification, InfiniTime implement custom services. As all BLE services, custom services are identified by a UUID. Here is how to define the UUID of custom services in InfiniTime:
+When the service does not exist in the BLE specification, InfiniTime implements custom services. Custom services are identified by a UUID, as are all BLE services. Here is how to define the UUID of custom services in InfiniTime:
```
- Base UUID : xxxxxxxx-78fc-48fe-8e23-433b3a1942d0
@@ -38,6 +74,8 @@ The following custom services are implemented in InfiniTime:
* Navigation Service : 00010000-78fc-48fe-8e23-433b3a1942d0
```
+---
+
## BLE services
[List of standard BLE services](https://www.bluetooth.com/specifications/gatt/services/)
@@ -49,3 +87,197 @@ The following custom services are implemented in InfiniTime:
![ANS sequence diagram](./ble/ans_sequence.png "ANS sequence diagram")
+---
+
+### Getting Information
+
+The InfiniTime firmware exposes some information about itself through BLE. The BLE characteristic UUIDs for this information are as follows:
+
+- Firmware Version: `00002a26-0000-1000-8000-00805f9b34fb`
+- Battery Level: `00002a19-0000-1000-8000-00805f9b34fb`
+- Heart Rate: `00002a37-0000-1000-8000-00805f9b34fb`
+
+#### Firmware Version
+
+Reading a value from the firmware version characteristic will yield a UTF-8 encoded string containing the version of InfiniTime being run on the device. Example: `1.6.0`.
+
+#### Battery Level
+
+Reading from the battery level characteristic yields a single byte of data. This byte can be converted to an unsigned 8-bit integer which will be the battery percentage. This characteristic allows notify for updates as the value changes.
+
+#### Heart Rate
+
+Reading from the heart rate characteristic yields two bytes of data. I am not sure of the function of the first byte. It appears to always be zero. The second byte can be converted to an unsigned 8-bit integer which is the current heart rate. This characteristic also allows notify for updates as the value changes.
+
+---
+
+### Notifications
+
+InfiniTime uses the Alert Notification Service (ANS) for notifications. The relevant UUIDs are as follows:
+
+- New Alert: `00002a46-0000-1000-8000-00805f9b34fb`
+- Notification Event: `00020001-78fc-48fe-8e23-433b3a1942d0`
+
+#### New Alert
+
+The new alert characteristic allows sending new notifications to InfiniTime. It requires the following format:
+
+```
+<category><amount>\x00<\x00-separated data>
+```
+
+For example, here is what a normal notification looks like in Golang (language of `itd`):
+
+```go
+// \x00 is the category for simple alert, and there is one new notifcation, hence \x01.
+"\x00\x01\x00Test Title\x00Test Body"
+```
+
+A call notification looks like so:
+
+```go
+// \x03 is the category for calls, and there is one new call notifcation, hence \x01.
+"\x03\x01\x00Mary"
+```
+
+The `\x00` stands for hexadecimal `00` which means null.
+
+Here is the list of categories and commands:
+
+- Simple Alert: `0`
+- Email: `1`
+- News: `2`
+- Call Notification: `3`
+- Missed Call: `4`
+- SMS/MMS: `5`
+- Voicemail: `6`
+- Schedule: `7`
+- High Prioritized Alert: `8`
+- Instant Message: `9`
+- All Alerts: `0xFF`
+
+These lists and information were retrieved from the following pages in the Nordic docs:
+
+- [Alert Notification Service Client](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.2.0%2Fgroup__ble__ans__c.html)
+- [Alert Notification Application](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v13.0.0%2Fble_sdk_app_alert_notification.html)
+
+#### Notification Event
+
+A call notification in InfiniTime contains three buttons. Decline, Accept, and Mute. The notification event characteristic contains the button tapped by the user on a call notification. This characteristic only allows notify, **not** read.
+
+Enabling notifications from this characteristic, you get a single byte whenever the user taps a button on the call notification. This byte is an unsigned 8-bit integer that signifies one of the buttons. The numbers are as follows:
+
+- 0: Declined
+- 1: Accepted
+- 2: Muted
+
+---
+
+### Firmware Upgrades
+
+Firmware upgrades in InfiniTime are probably the most complex of the BLE operations. It is a nine step process requiring multiple commands be sent to multiple characteristics. The relevant UUIDs are as follows:
+
+- Control Point: `00001531-1212-efde-1523-785feabcd123`
+- Packet: `00001532-1212-efde-1523-785feabcd123`
+
+A DFU upgrade archive for InfiniTime consists of multiple files. The most important being the .bin and .dat files. The first is the actual firmware, while the second is a packet that initializes DFU. Both are needed for a DFU upgrade.
+
+The first thing to do is to enable notifications on the control point characteristic. This will be needed for verifying that the proper responses are being sent back from InfiniTime.
+
+#### Step one
+
+For the first step, write `0x01`, `0x04` to the control point characteristic. This will signal InfiniTime that a DFU upgrade is to be started.
+
+#### Step two
+
+In step two, send the total size in bytes of the firmware file to the packet characteristic. This value should be an unsigned 32-bit integer encoded as little-endian. In front of this integer should be 8 null bytes. This is because there are three items that can be updated and each 4 bytes is for one of those. The last four are for the InfiniTime application, so those are the ones that need to be set.
+
+#### Step three
+
+Before running step three, wait for a response from the control point. This response should be `0x10`, `0x01`, `0x01` which indicates a successful DFU start. In step three, send `0x02`, `0x00` to the control point. This will signal InfiniTime to expect the init packet on the packet characteristic.
+
+#### Step four
+
+The previous step prepared InfiniTime for this one. In this step, send the contents of the .dat init packet file to the packet characteristic. After this, send `0x02`, `0x01` indicating that the packet has been sent.
+
+#### Step five
+
+Before running this step, wait to receive `0x10`, `0x02`, `0x01` which indicates that the packet has been received. During this step, send the packet receipt interval to the control point. The firmware file will be sent in segments of 20 bytes each. The packet receipt interval indicates how many segments should be received before sending a receipt containing the amount of bytes received so that it can be confirmed to be the same as the amount sent. This is very useful for detecting packet loss. `itd` uses `0x08`, `0x0A` which indicates 10 segments.
+
+#### Step six
+
+In step six, write `0x03` to the control point, indicating that the firmware will be sent next on the packet characteristic.
+
+#### Step seven
+
+This step is the most difficult. Here, the actual firmware is sent to InfiniTime.
+
+As mentioned before, the firmware file must be split up into segments of 20 bytes each and sent to the packet characteristic one by one. Every 10 segments (or whatever you have set the interval to), check for a response starting with `0x11`. The rest of the response will be the amount of bytes received encoded as a little-endian unsigned 32-bit integer. Confirm that this matches the amount of bytes sent, and then continue sending more segments.
+
+#### Step eight
+
+Before running this step, wait to receive `0x10`, `0x03`, `0x01` which indicates a successful receipt of the firmware image. In this step, write `0x04` to the control point to signal InfiniTime to validate the image it has received.
+
+#### Step nine
+
+Before running this step, wait to receive `0x10`, `0x04`, `0x01` which indicates that the image has been validated. In this step, send `0x05` to the control point as a command with no response. This signals InfiniTime to activate the new firmware and reboot.
+
+Once all of these steps are complete, the DFU is complete. Don't forget to validate the firmware in the settings.
+
+---
+
+### Music Control
+
+InfiniTime contains a music controller app which is meant to control the music playback and volume through the companion.
+
+The following UUIDs are relevant to this:
+
+- Events: `00000001-78fc-48fe-8e23-433b3a1942d0`
+- Status: `00000002-78fc-48fe-8e23-433b3a1942d0`
+- Artist: `00000003-78fc-48fe-8e23-433b3a1942d0`
+- Track: `00000004-78fc-48fe-8e23-433b3a1942d0`
+- Album: `00000005-78fc-48fe-8e23-433b3a1942d0`
+
+#### Events
+
+The events characteristic is meant to respond to user input in the music controller app.
+
+Enabling notifications on this characteristic gives you a single byte upon any event. This byte can be converted to an unsigned 8-bit integer which corresponds to each possible event. Here are the events:
+
+- App Opened: `0xe0`
+- Play: `0x00`
+- Pause: `0x01`
+- Next: `0x03`
+- Previous: `0x04`
+- Volume up: `0x05`
+- Volume down: `0x06`
+
+#### Status
+
+The status characteristic allows setting the playing status of music. Send `0x01` to the status characteristic for playing, and `0x00` for paused.
+
+#### Artist, Track, and Album
+
+These characteristics all work the same way. Simply send a UTF-8 encoded string to the relevant characteristic in order to set the value in the app.
+
+---
+
+### Time
+
+InfiniTime allows setting its time via the Current Time Service (CTS)
+
+The UUID for the current time characteristic is: `00002a2b-0000-1000-8000-00805f9b34fb`
+
+This characteristic expects a particular format:
+
+- Year (`uint16`)
+- Month (`uint8`)
+- Day (`uint8`)
+- Hour (`uint8`)
+- Minute (`uint8`)
+- Second (`uint8`)
+- Weekday (`uint8`)
+- Microsecond divided by `1e6*256` (`uint8`)
+- Binary 0001 (`uint8`)
+
+Write all of these together, encoded as little-endian, to the current time characteristic. \ No newline at end of file
diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md
index e97bb30d..3e000a3a 100644
--- a/doc/buildAndProgram.md
+++ b/doc/buildAndProgram.md
@@ -3,13 +3,20 @@
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
+ - The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt))
+ - To to keep the system clean a python virtual environment (`venv`) can be used to install the python modules into
+ ```sh
+ python -m venv .venv
+ source .venv/bin/activate
+ python -m pip install wheel
+ python -m pip install -r tools/mcuboot/requirements.txt
+ ```
- A reasonably recent version of CMake (I use 3.16.5)
## Build steps
### Clone the repo
```
-git clone https://github.com/JF002/InfiniTime.git
+git clone https://github.com/InfiniTimeOrg/InfiniTime.git
cd InfiniTime
git submodule update --init
mkdir build
@@ -31,9 +38,9 @@ CMake configures the project according to variables you specify the command line
**WATCH_COLMI_P8**|Use pin configuration for Colmi P8 watch|`-DWATCH_COLMI_P8=1`
####(**) Note about **CMAKE_BUILD_TYPE**:
-By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/JF002/InfiniTime/releases) new versions of InfiniTime.
+By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/InfiniTimeOrg/InfiniTime/releases) new versions of InfiniTime.
-The *Debug* mode disables all optimizations, which makes the code easier to debug. However, the binary size will likely be too big to fit in the internal flash memory. If you want to build and debug a *Debug* binary, you'll need to disable some parts of the code. For example, the icons for the **Navigation** app use a lot of memory space. You can comment the content of `m_iconMap` in the [Navigation](https://github.com/JF002/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory.
+The *Debug* mode disables all optimizations, which makes the code easier to debug. However, the binary size will likely be too big to fit in the internal flash memory. If you want to build and debug a *Debug* binary, you'll need to disable some parts of the code. For example, the icons for the **Navigation** app use a lot of memory space. You can comment the content of `m_iconMap` in the [Navigation](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory.
####(**) Note about **BUILD_DFU**:
DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mecanism. To generate the DFU file, the Python tool [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) is needed on your system. Check that this tool is properly installed before enabling this option.
diff --git a/doc/buildWithDocker.md b/doc/buildWithDocker.md
index 2e4ecbb6..a57893c9 100644
--- a/doc/buildWithDocker.md
+++ b/doc/buildWithDocker.md
@@ -11,7 +11,9 @@ Based on Ubuntu 18.04 with the following build dependencies:
## Run a container to build the project
-The `infinitime-build` image contains all the dependencies you need. The default `CMD` will compile sources found in `/sources`, so you need only mount your code.
+The `infinitime-build` image contains all the dependencies you need. The default `CMD` will compile sources found in `/sources`, so you need only mount your code.
+
+Before continuing, make sure you first build the image as indicated in the [Build the image](#build-the-image) section, or check the [Using the image from Docker Hub](#using-the-image-from-docker-hub) section if you prefer to use a pre-made image.
This example will build the firmware, generate the MCUBoot image and generate the DFU file. For cloning the repo, see [these instructions](../doc/buildAndProgram.md#clone-the-repo). Outputs will be written to **<project_root>/build/output**:
@@ -28,10 +30,10 @@ docker run --rm -it -v $(pwd):/sources infinitime-build /opt/build.sh pinetime-a
The image is built using 1000:1000 for the user id and group id. If this is different to your user or group ids (run `id -u` and `id -g` to find out what your id values are if you are unsure), you will need to override them via the `--user` parameter in order to prevent permission errors with the output files (and the cmake build cache).
-Running with this image is the same as above, you just specify the ids to `docker run`
+Running with this image is the same as above, you just specify the ids to `docker run`:
```bash
-docker run --rm -it -v $(pwd):/sources --user $(id -u):$(id -g) pfeerick/infinitime-build
+docker run --rm -it -v $(pwd):/sources --user $(id -u):$(id -g) infinitime-build
```
Or you can specify your user id and group id (by number, not by name) directly:
@@ -42,7 +44,7 @@ docker run --rm -it -v $(pwd):/sources --user 1234:1234 infinitime-build
## Using the image from Docker Hub
-The image is avaiable via Docker Hub for both the amd64 and arm64v8 architectures at [pfeerick/infinitime-build](https://hub.docker.com/repository/docker/pfeerick/infinitime-build).
+The image is available via Docker Hub for both the amd64 and arm64v8 architectures at [pfeerick/infinitime-build](https://hub.docker.com/r/pfeerick/infinitime-build).
It can be pulled (downloaded) using the following command:
diff --git a/doc/buildWithVScode.md b/doc/buildWithVScode.md
index c1df17b7..23c97145 100644
--- a/doc/buildWithVScode.md
+++ b/doc/buildWithVScode.md
@@ -36,7 +36,17 @@ Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemNam
More documentation is available in the [readme in .devcontainer](.devcontainer/readme.md)
-
+### DevContainer on Ubuntu
+To use the DevContainer configuration on Ubuntu based systems two changes need to be made:
+
+1. Modify the file ``.devcontainer/devcontainer.json`` and add the argument ``"--net=host"`` to the ``"runArgs"`` parameter making the line look like this:
+`` "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", "--net=host"],
+``
+2. Modify the file ``.vscode/launch.json`` and change the argument of ``"gdbTarget"`` to ``"127.0.0.1:3333"``, making the line look like:
+``"gdbTarget": "127.0.0.1:3333",``
+3. To start debugging launch openocd on your host system with the appropriate configuration, for example with a stlink-v2 the command is:
+``openocd -f interface/stlink.cfg -f target/nrf52.cfg``. This launches openocd with the default ports ``3333``, ``4444`` and ``6666``.
+4. In VsCode go to the Debug pane on the left of the screen and select the configuration ``Debug - Openocd docker Remote`` and hit the play button on the left.
diff --git a/doc/code/Apps.md b/doc/code/Apps.md
new file mode 100644
index 00000000..7c2d7a05
--- /dev/null
+++ b/doc/code/Apps.md
@@ -0,0 +1,106 @@
+# Apps
+This page will teach you:
+- what apps in InfiniTime are
+- how to implement your own app
+
+## Theory
+Apps are the things you can launch from the app selection you get by swiping up.
+At the moment, settings and even the app launcher itself or the clock are implemented very similarly, this might change in the future though.
+Every app in InfiniTime is it's own class.
+An instance of the class is created when the app is launched and destroyed when the user exits the app.
+They run inside the "displayapp" task (briefly discussed [here](./Intro.md)).
+Apps are responsible for everything drawn on the screen when they are running.
+By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected.
+
+## Interface
+Every app class has to be inside the namespace `Pinetime::Applications::Screens` and inherit from `Screen`.
+The constructor should have at least one parameter `DisplayApp* app`, which it needs for the constructor of its parent class Screen.
+Other parameters should be references to controllers that the app needs.
+A destructor is needed to clean up LVGL and restore any changes (for example re-enable sleeping).
+App classes can override `bool OnButtonPushed()`, `bool OnTouchEvent(TouchEvents event)` and `bool OnTouchEvent(uint16_t x, uint16_t y)` to implement their own functionality for those events.
+If an app only needs to display some text and do something upon a touch screen button press,
+it does not need to override any of these functions, as LVGL can also handle touch events for you.
+If you have any doubts, you can always look at how the other apps are doing things.
+
+### Continuous updating
+If your app needs to be updated continuously, yo can do so by overriding the `Refresh()` function in your class
+and calling `lv_task_create` inside the constructor.
+An example call could look like this: <br>
+`taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);` <br>
+With `taskRefresh` being a member variable of your class and of type `lv_task_t*`.
+Remember to delete the task again using `lv_task_del`.
+The function `RefreshTaskCallback` is inherited from screen and just calls your `Refresh` function.
+
+### Apps with multiple screens
+InfiniTime provides a mini-library in [displayapp/screens/ScreenList.h](/src/displayapp/screens/ScreenList.h)
+which makes it relatively easy to add multiple screens to your app.
+To use it, #include it in the header file of your app and add a ScreenList member to your class.
+The template argument should be the number of screens you need.
+You will also need to add `CreateScreen` functions that return `std::unique_ptr<Screen>`
+to your class, one for every screen you have.
+There are still some things left to to that I won't cover here.
+To figure them out, have a look at the "apps" ApplicationList, Settings and SystemInfo.
+
+
+## Creating your own app
+A minimal app could look like this: <br>
+MyApp.h:
+```cpp
+#pragma once
+
+#include "displayapp/screens/Screen.h"
+#include <lvgl/lvgl.h>
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class MyApp : public Screen {
+ public:
+ MyApp(DisplayApp* app);
+ ~MyApp() override;
+ };
+ }
+ }
+}
+```
+
+MyApp.cpp:
+```cpp
+#include "MyApp.h"
+#include "displayapp/DisplayApp.h"
+
+using namespace Pinetime::Applications::Screens;
+
+MyApp::MyApp(DisplayApp* app) : Screen(app) {
+ lv_obj_t* title = lv_label_create(lv_scr_act(), NULL);
+ lv_label_set_text_static(title, "My test application");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+}
+
+MyApp::~MyApp() {
+ lv_obj_clean(lv_scr_act());
+}
+```
+Both of these files should be in [displayapp/screens/](/src/displayapp/screens/)
+or [displayapp/screens/settings/](/src/displayapp/screens/settings/) if it's a setting app.
+
+Now we have our very own app, but InfiniTime does not know about it yet.
+The first step is to include your MyApp.cpp (or any new cpp files for that matter)
+in the compilation by adding it to [CMakeLists.txt](/CMakeLists.txt).
+The next step to making it launchable is to give your app an id.
+To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/Apps.h](/src/displayapp/Apps.h)).
+Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
+Now, go to the function `DisplayApp::LoadApp` and add another case to the switch statement.
+The case will be the id you gave your app earlier.
+If your app needs any additional arguments, this is the place to pass them.
+
+If you want your app to be launched from the regular app launcher, go to [displayapp/screens/ApplicationList.cpp](/src/displayapp/screens/ApplicationList.cpp).
+Add your app to one of the `CreateScreen` functions, or add another `CreateScreen` function if there are no empty spaces for your app. <br>
+If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.cpp](/src/displayapp/screens/settings/Settings.cpp).
+
+You should now be able to [build](../buildAndProgram.md) the firmware
+and flash it to your PineTime. Yay!
+
+Please remember to pay attention to the [UI guidelines](../ui_guidelines.md)
+when designing an app that you want to include in mainstream InfiniTime.
diff --git a/doc/code/Intro.md b/doc/code/Intro.md
new file mode 100644
index 00000000..762102fe
--- /dev/null
+++ b/doc/code/Intro.md
@@ -0,0 +1,42 @@
+# Introduction to the code
+This page is meant to guide you through the source code, so you can find the relevant files for what you're working on.
+
+## FreeRTOS
+Infinitime is based on FreeRTOS, a real-time operating system.
+FreeRTOS provides several quality of life abstractions (for example easy software timers)
+and most importantly supports multiple tasks.
+If you want to read up on real-time operating systems, you can look [here](https://www.freertos.org/implementation/a00002.html) and [here](https://www.freertos.org/features.html).
+The main "process" creates at least one task and then starts the FreeRTOS task scheduler.
+This main "process" is the standard main() function inside [main.cpp](/src/main.cpp).
+The task scheduler is responsible for giving every task enough cpu time.
+As there is only one core on the SoC of the PineTime, real concurrency is impossible and the scheduler has to swap tasks in and out to emulate it.
+
+### Tasks
+Tasks are created by calling `xTaskCreate` and passing a function with the signature `void functionName(void*)`.
+For more info on task creation see the [FreeRTOS Documentation](https://www.freertos.org/a00125.html).
+In our case, main calls `systemTask.Start()`, which creates the **"MAIN" task**.
+The function running inside that task is `SystemTask::Work()`.
+You may also see this task being referred to as the **work task**.
+Both functions are located inside [systemtask/SystemTask.cpp](/src/systemtask/SystemTask.cpp). `SystemTask::Work()` initializes all the driver and controller objects.
+It also starts the **task "displayapp"**, which is responsible for launching and running apps, controlling the screen and handling touch events (or forwarding them to the active app).
+You can find the "displayapp" task inside [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
+There are also other tasks that are responsible for Bluetooth ("ll" and "ble" inside [libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c](/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c))
+and periodic tasks like heartrate measurements ([heartratetask/HeartRateTask.cpp](/src/heartratetask/HeartRateTask.cpp)). <br>
+While it is possible for you to create your own task when you need it, it is recommended to just add functionality to `SystemTask::Work()` if possible.
+If you absolutely need to create another task, try to guess how much [stack space](https://www.freertos.org/FAQMem.html#StackSize) (in words/4-byte packets)
+it will need instead of just typing in a large-ish number.
+You can use the define `configMINIMAL_STACK_SIZE` which is currently set to 120 words.
+
+## Controllers
+Controllers in InfiniTime are singleton objects that can provide access to certain resources to apps.
+Some of them interface with drivers, others are the driver for the resource.
+The resources provided don't have to be hardware-based.
+They are declared in main.cpp and initialized in [systemtask/SystemTask.cpp](/src/systemtask/SystemTask.cpp).
+Some controllers can be passed by reference to apps that need access to the resource (for example vibration motor).
+They reside in [components/](/src/components/) inside their own subfolder.
+
+## Apps
+For more detail see the [Apps page](./Apps.md)
+
+## Bluetooth
+Header files with short documentation for the functions are inside [libs/mynewt-nimble/nimble/host/include/host/](/src/libs/mynewt-nimble/nimble/host/include/host/).
diff --git a/doc/contribute.md b/doc/contribute.md
index 0c34e2a5..595a5996 100644
--- a/doc/contribute.md
+++ b/doc/contribute.md
@@ -2,7 +2,7 @@
## Report bugs
-Have you found a bug in the firmware? [Create an issue on Github](https://github.com/JF002/InfiniTime/issues) explaining the bug, how to reproduce it, the version of the firmware you use...
+Have you found a bug in the firmware? [Create an issue on Github](https://github.com/InfiniTimeOrg/InfiniTime/issues) explaining the bug, how to reproduce it, the version of the firmware you use...
## Write and improve documentation
@@ -18,18 +18,18 @@ You want to fix a bug, add a cool new functionality or improve the code? See *Ho
The Pinetime is a cool open source project that deserves to be known. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open source firmware for a smartwatch!
-# How to submit a pull request ?
+# How to submit a pull request?
## TL;DR
- - Create a branch from develop;
- - Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...);
- - Test your modifications on the actual hardware;
- - Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy);
- - Clean your code and remove files that are not needed;
- - Write documentation related to your new feature if applicable;
- - Create a pull request and write a great description about it : what does your PR do, why, how,... Add pictures and video if possible;
- - Wait for someone to review your PR and take part in the review process;
+ - Create a branch from develop
+ - Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...)
+ - Test your modifications on the actual hardware
+ - Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy)
+ - Clean your code and remove files that are not needed
+ - Write documentation related to your new feature if applicable
+ - Create a pull request and write a great description about it: what does your PR do, why, how,... Add pictures and video if possible
+ - Wait for someone to review your PR and take part in the review process
- Your PR will eventually be merged :)
Your contributions are more than welcome!
@@ -94,3 +94,10 @@ If there are no preconfigured rules for your IDE, you can use one of the existin
- **Includes** :
- files from the project : `#include "relative/path/to/the/file.h"`
- external files and std : `#include <file.h>`
+ - Only use [primary spellings for operators and tokens](https://en.cppreference.com/w/cpp/language/operator_alternative)
+ - Use auto sparingly. Don't use auto for [fundamental/built-in types](https://en.cppreference.com/w/cpp/language/types) and [fixed width integer types](https://en.cppreference.com/w/cpp/types/integer), except when initializing with a cast to avoid duplicating the type name.
+ - Examples:
+ - `auto* app = static_cast<DisplayApp*>(instance);`
+ - `auto number = static_cast<uint8_t>(variable);`
+ - `uint8_t returnValue = MyFunction();`
+ - Use nullptr instead of NULL
diff --git a/doc/filesInReleaseNotes.md b/doc/filesInReleaseNotes.md
index 1a37fefb..6a5873c0 100644
--- a/doc/filesInReleaseNotes.md
+++ b/doc/filesInReleaseNotes.md
@@ -1,9 +1,9 @@
# Using the releases
-For each new *stable* version of IniniTime, a [release note](https://github.com/JF002/InfiniTime/releases) is created. It contains a description of the main changes in the release and some files you can use to flash the firmware to your Pinetime.
+For each new *stable* version of IniniTime, a [release note](https://github.com/InfiniTimeOrg/InfiniTime/releases) is created. It contains a description of the main changes in the release and some files you can use to flash the firmware to your Pinetime.
This page describes the files from the release notes and how to use them.
-**NOTE :** the files included in different Releases could be different. This page describes the release notes of [version 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1), which is the version that is pre-programmed for the last batches of pinetimes but will be replaced with [1.0.0](https://github.com/jF002/infiniTime/releases/tag/1.0.0) around june 2021.
+**NOTE :** the files included in different Releases could be different. This page describes the release notes of [version 0.7.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.7.1), which is the version that is pre-programmed for the last batches of pinetimes but will be replaced with [1.0.0](https://github.com/jF002/infiniTime/releases/tag/1.0.0) around june 2021.
## Files included in the release notes
diff --git a/doc/gettingStarted/gettingStarted-1.0.md b/doc/gettingStarted/gettingStarted-1.0.md
index 88ff2072..3f8f38f6 100644
--- a/doc/gettingStarted/gettingStarted-1.0.md
+++ b/doc/gettingStarted/gettingStarted-1.0.md
@@ -8,15 +8,15 @@ You might have already seen these words by reading the announcement, release not
Basically, a **firmware** is just a software running on the embedded hardware of a device, the PineTime in this case.
**InfiniTime** is based on 3 distinct **firmwares**:
- - **[InfiniTime](https://github.com/JF002/InfiniTime)** itself, this is the *application firmware* running on the PineTime. This is the main firmware which provides most of the functionalities you'll use on a daily basis : bluetooth low-energy (BLE) connectivity, applications, watchfaces,...
+ - **[InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)** itself, this is the *application firmware* running on the PineTime. This is the main firmware which provides most of the functionalities you'll use on a daily basis : bluetooth low-energy (BLE) connectivity, applications, watchfaces,...
- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying **updates** of the *application firmware*, reverting them in case of issues and load the recovery firmware when requested.
- - **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/JF002/InfiniTime/releases/tag/0.14.1).
+ - **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1).
**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**igital **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).
## How to check the version of InfiniTime and the bootloader?
-Since September 2020, all PineTimes (devkits or sealed) are flashed using the **[first iteration of the bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7)** and **[InfiniTime 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1)**. There was no recovery firmware at that time.
+Since September 2020, all PineTimes (devkits or sealed) are flashed using the **[first iteration of the bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7)** and **[InfiniTime 0.7.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.7.1)**. There was no recovery firmware at that time.
The bootloader only runs when the watch starts (from an empty battery, for example) or after a reset (after a successful OTA or a manual reset - long push on the button).
@@ -33,7 +33,7 @@ And for version >= 1.0 :
![InfiniTime 1.0 version](version-1.0.jpg)
-PineTime shipped from June 2021 (to be confirmed) will be flashed with the [new version of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0), the [recovery firmware](https://github.com/JF002/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/tag/1.0.0).
+PineTime shipped from June 2021 (to be confirmed) will be flashed with the [new version of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0), the [recovery firmware](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/1.0.0).
The bootloader is easily recognizable with it white pine cone that is progressively drawn in green. It also displays its own version on the bottom (1.0.0 as of now).
@@ -56,9 +56,9 @@ If your PineTime is currently running InfiniTime 0.7.1 and the old bootloader, w
Using the companion app of your choice, you'll need to apply the OTA procedure for these 3 firmwares in this sequence (failing to follow this specific order might temporarily or permanently brick your device):
- 1. Flash the latest version of InfiniTime. The file to upload is named **pinetime-mcuboot-app-dfu-x.y.z.zip**. Here is the link to [InfiniTime 1.0](https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip).
+ 1. Flash the latest version of InfiniTime. The file to upload is named **pinetime-mcuboot-app-dfu-x.y.z.zip**. Here is the link to [InfiniTime 1.0](https://github.com/InfiniTimeOrg/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip).
2. Update the bootloader by applying the OTA procedure with the file named [**reloader-mcuboot.zip** from the repo of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/download/1.0.0/reloader-mcuboot.zip).
- 3. Install the recovery firmware by applying the OTA procedure with the file named [**pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip** from the version 0.14.1 of InfiniTime](https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip).
+ 3. Install the recovery firmware by applying the OTA procedure with the file named [**pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip** from the version 0.14.1 of InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip).
You'll find more info about this process in [this wiki page](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0). You can also see the procedure in video [here](https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529) and [here (from Amazfish)](https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e)
diff --git a/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md b/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md
index ffc27ed8..57d16218 100644
--- a/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md
+++ b/doc/gettingStarted/ota-gadgetbridge-nrfconnect.md
@@ -8,7 +8,7 @@ If you just want to flash or upgrade InfiniTime on your PineTime, this page is f
- [How to flash InfiniTime using the SWD interface](#how-to-flash-infinitime-using-the-swd-interface)
## InfiniTime releases and versions
-All releases of InfiniTime are available on the [release page of the GitHub repo](https://github.com/JF002/InfiniTime/releases).
+All releases of InfiniTime are available on the [release page of the GitHub repo](https://github.com/InfiniTimeOrg/InfiniTime/releases).
Versions that are tagged as **RELEASE CANDIDATE** are pre-release versions, that are available for testing before actually releasing a new stable version. If you want to help us debug the project and provide stable versions to other user, you can use them. If you want stable and tested version, you should not flash these release candidate version.
diff --git a/docker/build.sh b/docker/build.sh
index 2fa7d920..d86e7c21 100755
--- a/docker/build.sh
+++ b/docker/build.sh
@@ -43,7 +43,7 @@ GetGcc() {
}
GetMcuBoot() {
- git clone https://github.com/JuulLabs-OSS/mcuboot.git "$TOOLS_DIR/mcuboot"
+ git clone https://github.com/mcu-tools/mcuboot.git "$TOOLS_DIR/mcuboot"
pip3 install -r "$TOOLS_DIR/mcuboot/scripts/requirements.txt"
}
diff --git a/gcc_nrf52-mcuboot.ld b/gcc_nrf52-mcuboot.ld
index 0746f491..81b318c5 100644
--- a/gcc_nrf52-mcuboot.ld
+++ b/gcc_nrf52-mcuboot.ld
@@ -6,12 +6,18 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08020, LENGTH = 0x78000
- RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
+ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
-}
+ .noinit(NOLOAD):
+ {
+ PROVIDE(__start_noinit_data = .);
+ *(.noinit)
+ PROVIDE(__stop_noinit_data = .);
+ } > RAM
+} INSERT AFTER .bss
SECTIONS
{
diff --git a/gcc_nrf52.ld b/gcc_nrf52.ld
index 98e133aa..f9bc5b68 100644
--- a/gcc_nrf52.ld
+++ b/gcc_nrf52.ld
@@ -6,12 +6,18 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000, LENGTH = 0x78000
- RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
+ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
-}
+ .noinit(NOLOAD):
+ {
+ PROVIDE(__start_noinit_data = .);
+ *(.noinit)
+ PROVIDE(__stop_noinit_data = .);
+ } > RAM
+} INSERT AFTER .bss
SECTIONS
{
@@ -44,6 +50,7 @@ SECTIONS
PROVIDE(__stop_log_filter_data = .);
} > RAM
+
} INSERT AFTER .data;
SECTIONS
diff --git a/src/BootErrors.h b/src/BootErrors.h
new file mode 100644
index 00000000..d00418cc
--- /dev/null
+++ b/src/BootErrors.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace Pinetime {
+ namespace System {
+ enum class BootErrors {
+ None,
+ TouchController,
+ };
+ }
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index be406ba4..07eabe11 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -421,6 +421,8 @@ list(APPEND SOURCE_FILES
displayapp/screens/BatteryInfo.cpp
displayapp/screens/Steps.cpp
displayapp/screens/Timer.cpp
+ displayapp/screens/Error.cpp
+ displayapp/screens/Alarm.cpp
displayapp/Colors.cpp
## Settings
@@ -432,6 +434,8 @@ list(APPEND SOURCE_FILES
displayapp/screens/settings/SettingDisplay.cpp
displayapp/screens/settings/SettingSteps.cpp
displayapp/screens/settings/SettingPineTimeStyle.cpp
+ displayapp/screens/settings/SettingSetDate.cpp
+ displayapp/screens/settings/SettingSetTime.cpp
## Watch faces
displayapp/icons/bg_clock.c
@@ -477,6 +481,7 @@ list(APPEND SOURCE_FILES
components/motor/MotorController.cpp
components/settings/Settings.cpp
components/timer/TimerController.cpp
+ components/alarm/AlarmController.cpp
components/fs/FS.cpp
drivers/Cst816s.cpp
FreeRTOS/port.c
@@ -543,6 +548,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/firmwarevalidator/FirmwareValidator.cpp
components/settings/Settings.cpp
components/timer/TimerController.cpp
+ components/alarm/AlarmController.cpp
drivers/Cst816s.cpp
FreeRTOS/port.c
FreeRTOS/port_cmsis_systick.c
@@ -615,6 +621,7 @@ set(INCLUDE_FILES
displayapp/screens/Metronome.h
displayapp/screens/Motion.h
displayapp/screens/Timer.h
+ displayapp/screens/Alarm.h
displayapp/Colors.h
drivers/St7789.h
drivers/SpiNorFlash.h
@@ -647,6 +654,7 @@ set(INCLUDE_FILES
components/ble/HeartRateService.h
components/settings/Settings.h
components/timer/TimerController.h
+ components/alarm/AlarmController.h
drivers/Cst816s.h
FreeRTOS/portmacro.h
FreeRTOS/portmacro_cmsis.h
diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp
new file mode 100644
index 00000000..67ca05a9
--- /dev/null
+++ b/src/components/alarm/AlarmController.cpp
@@ -0,0 +1,114 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "AlarmController.h"
+#include "systemtask/SystemTask.h"
+#include "app_timer.h"
+#include "task.h"
+#include <chrono>
+
+using namespace Pinetime::Controllers;
+using namespace std::chrono_literals;
+
+AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
+}
+
+APP_TIMER_DEF(alarmAppTimer);
+
+namespace {
+ void SetOffAlarm(void* p_context) {
+ auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(p_context);
+ if (controller != nullptr) {
+ controller->SetOffAlarmNow();
+ }
+ }
+}
+
+void AlarmController::Init(System::SystemTask* systemTask) {
+ app_timer_create(&alarmAppTimer, APP_TIMER_MODE_SINGLE_SHOT, SetOffAlarm);
+ this->systemTask = systemTask;
+}
+
+void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
+ hours = alarmHr;
+ minutes = alarmMin;
+}
+
+void AlarmController::ScheduleAlarm() {
+ // Determine the next time the alarm needs to go off and set the app_timer
+ app_timer_stop(alarmAppTimer);
+
+ auto now = dateTimeController.CurrentDateTime();
+ alarmTime = now;
+ time_t ttAlarmTime = std::chrono::system_clock::to_time_t(alarmTime);
+ tm* tmAlarmTime = std::localtime(&ttAlarmTime);
+
+ // If the time being set has already passed today,the alarm should be set for tomorrow
+ if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) {
+ tmAlarmTime->tm_mday += 1;
+ // tm_wday doesn't update automatically
+ tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7;
+ }
+
+ tmAlarmTime->tm_hour = hours;
+ tmAlarmTime->tm_min = minutes;
+ tmAlarmTime->tm_sec = 0;
+
+ // if alarm is in weekday-only mode, make sure it shifts to the next weekday
+ if (recurrence == RecurType::Weekdays) {
+ if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day
+ tmAlarmTime->tm_mday += 1;
+ } else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days
+ tmAlarmTime->tm_mday += 2;
+ }
+ }
+ tmAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST
+
+ // now can convert back to a time_point
+ alarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmAlarmTime));
+ auto mSecToAlarm = std::chrono::duration_cast<std::chrono::milliseconds>(alarmTime - now).count();
+ app_timer_start(alarmAppTimer, APP_TIMER_TICKS(mSecToAlarm), this);
+
+ state = AlarmState::Set;
+}
+
+uint32_t AlarmController::SecondsToAlarm() {
+ return std::chrono::duration_cast<std::chrono::seconds>(alarmTime - dateTimeController.CurrentDateTime()).count();
+}
+
+void AlarmController::DisableAlarm() {
+ app_timer_stop(alarmAppTimer);
+ state = AlarmState::Not_Set;
+}
+
+void AlarmController::SetOffAlarmNow() {
+ state = AlarmState::Alerting;
+ systemTask->PushMessage(System::Messages::SetOffAlarm);
+}
+
+void AlarmController::StopAlerting() {
+ systemTask->PushMessage(System::Messages::StopRinging);
+
+ // Alarm state is off unless this is a recurring alarm
+ if (recurrence == RecurType::None) {
+ state = AlarmState::Not_Set;
+ } else {
+ state = AlarmState::Set;
+ // set next instance
+ ScheduleAlarm();
+ }
+}
diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h
new file mode 100644
index 00000000..bf85d431
--- /dev/null
+++ b/src/components/alarm/AlarmController.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <cstdint>
+#include "app_timer.h"
+#include "components/datetime/DateTimeController.h"
+
+namespace Pinetime {
+ namespace System {
+ class SystemTask;
+ }
+ namespace Controllers {
+ class AlarmController {
+ public:
+ AlarmController(Controllers::DateTime& dateTimeController);
+
+ void Init(System::SystemTask* systemTask);
+ void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
+ void ScheduleAlarm();
+ void DisableAlarm();
+ void SetOffAlarmNow();
+ uint32_t SecondsToAlarm();
+ void StopAlerting();
+ enum class AlarmState { Not_Set, Set, Alerting };
+ enum class RecurType { None, Daily, Weekdays };
+ uint8_t Hours() const {
+ return hours;
+ }
+ uint8_t Minutes() const {
+ return minutes;
+ }
+ AlarmState State() const {
+ return state;
+ }
+ RecurType Recurrence() const {
+ return recurrence;
+ }
+ void SetRecurrence(RecurType recurType) {
+ recurrence = recurType;
+ }
+
+ private:
+ Controllers::DateTime& dateTimeController;
+ System::SystemTask* systemTask = nullptr;
+ uint8_t hours = 7;
+ uint8_t minutes = 0;
+ std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
+ AlarmState state = AlarmState::Not_Set;
+ RecurType recurrence = RecurType::None;
+ };
+ }
+}
diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp
index 4ef20a24..e807f033 100644
--- a/src/components/battery/BatteryController.cpp
+++ b/src/components/battery/BatteryController.cpp
@@ -13,10 +13,20 @@ Battery::Battery() {
nrf_gpio_cfg_input(PinMap::Charging, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Disabled);
}
-void Battery::Update() {
+void Battery::ReadPowerState() {
isCharging = !nrf_gpio_pin_read(PinMap::Charging);
isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent);
+ if (isPowerPresent && !isCharging) {
+ isFull = true;
+ } else if (!isPowerPresent) {
+ isFull = false;
+ }
+}
+
+void Battery::MeasureVoltage() {
+ ReadPowerState();
+
if (isReading) {
return;
}
@@ -63,18 +73,23 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024;
- if (voltage > battery_max) {
- percentRemaining = 100;
+ uint8_t newPercent;
+ if (isFull) {
+ newPercent = 100;
} else if (voltage < battery_min) {
- percentRemaining = 0;
+ newPercent = 0;
} else {
- percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
+ newPercent = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100);
+ }
+
+ if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) {
+ firstMeasurement = false;
+ percentRemaining = newPercent;
+ systemTask->PushMessage(System::Messages::BatteryPercentageUpdated);
}
nrfx_saadc_uninit();
isReading = false;
-
- systemTask->PushMessage(System::Messages::BatteryMeasurementDone);
}
}
diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h
index 8af27ea8..5a7394c4 100644
--- a/src/components/battery/BatteryController.h
+++ b/src/components/battery/BatteryController.h
@@ -10,7 +10,8 @@ namespace Pinetime {
public:
Battery();
- void Update();
+ void ReadPowerState();
+ void MeasureVoltage();
void Register(System::SystemTask* systemTask);
uint8_t PercentRemaining() const {
@@ -22,7 +23,9 @@ namespace Pinetime {
}
bool IsCharging() const {
- return isCharging;
+ // isCharging will go up and down when fully charged
+ // isFull makes sure this returns false while fully charged.
+ return isCharging && !isFull;
}
bool IsPowerPresent() const {
@@ -37,8 +40,10 @@ namespace Pinetime {
uint16_t voltage = 0;
uint8_t percentRemaining = 0;
+ bool isFull = false;
bool isCharging = false;
bool isPowerPresent = false;
+ bool firstMeasurement = true;
void SaadcInit();
diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp
index c3d1d69a..5e5c25cf 100644
--- a/src/components/ble/AlertNotificationClient.cpp
+++ b/src/components/ble/AlertNotificationClient.cpp
@@ -55,7 +55,7 @@ bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const
return true;
}
- if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ansServiceUuid), &service->uuid.u) == 0) {
+ if (service != nullptr && ble_uuid_cmp(&ansServiceUuid.u, &service->uuid.u) == 0) {
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
ansStartHandle = service->start_handle;
ansEndHandle = service->end_handle;
@@ -80,21 +80,21 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection
} else
onServiceDiscovered(connectionHandle);
} else {
- if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
+ if (characteristic != nullptr && ble_uuid_cmp(&supportedNewAlertCategoryUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
supportedNewAlertCategoryHandle = characteristic->val_handle;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&supportedUnreadAlertCategoryUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&newAlertUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
newAlertHandle = characteristic->val_handle;
newAlertDefHandle = characteristic->def_handle;
isCharacteristicDiscovered = true;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&unreadAlertStatusUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
unreadAlertStatusHandle = characteristic->val_handle;
- } else if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &controlPointUuid), &characteristic->uuid.u) == 0) {
+ } else if (characteristic != nullptr && ble_uuid_cmp(&controlPointUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
controlPointHandle = characteristic->val_handle;
} else
@@ -119,7 +119,7 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
uint16_t characteristicValueHandle,
const ble_gatt_dsc* descriptor) {
if (error->status == 0) {
- if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*) &newAlertUuid), &descriptor->uuid.u)) {
+ if (characteristicValueHandle == newAlertHandle && ble_uuid_cmp(&newAlertUuid.u, &descriptor->uuid.u)) {
if (newAlertDescriptorHandle == 0) {
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
newAlertDescriptorHandle = descriptor->handle;
diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp
index d5fc7f65..56fc595f 100644
--- a/src/components/ble/AlertNotificationService.cpp
+++ b/src/components/ble/AlertNotificationService.cpp
@@ -26,11 +26,8 @@ void AlertNotificationService::Init() {
}
AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager)
- : characteristicDefinition {{.uuid = (ble_uuid_t*) &ansCharUuid,
- .access_cb = AlertNotificationCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE},
- {.uuid = (ble_uuid_t*) &notificationEventUuid,
+ : characteristicDefinition {{.uuid = &ansCharUuid.u, .access_cb = AlertNotificationCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE},
+ {.uuid = &notificationEventUuid.u,
.access_cb = AlertNotificationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY,
@@ -39,7 +36,7 @@ AlertNotificationService::AlertNotificationService(System::SystemTask& systemTas
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &ansUuid,
+ .uuid = &ansUuid.u,
.characteristics = characteristicDefinition},
{0},
},
@@ -123,4 +120,4 @@ void AlertNotificationService::MuteIncomingCall() {
}
ble_gattc_notify_custom(connectionHandle, eventHandle, om);
-} \ No newline at end of file
+}
diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp
index 7f176904..29178667 100644
--- a/src/components/ble/BatteryInformationService.cpp
+++ b/src/components/ble/BatteryInformationService.cpp
@@ -14,7 +14,7 @@ int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController)
: batteryController {batteryController},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
+ characteristicDefinition {{.uuid = &batteryLevelUuid.u,
.access_cb = BatteryInformationServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
@@ -23,7 +23,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &batteryInformationServiceUuid,
+ .uuid = &batteryInformationServiceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
@@ -43,7 +43,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand
ble_gatt_access_ctxt* context) {
if (attributeHandle == batteryLevelHandle) {
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
- static uint8_t batteryValue = batteryController.PercentRemaining();
+ uint8_t batteryValue = batteryController.PercentRemaining();
int res = os_mbuf_append(context->om, &batteryValue, 1);
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp
index c6e68312..90d1f0c7 100644
--- a/src/components/ble/CurrentTimeClient.cpp
+++ b/src/components/ble/CurrentTimeClient.cpp
@@ -47,7 +47,7 @@ bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_ga
return true;
}
- if (service != nullptr && ble_uuid_cmp(((ble_uuid_t*) &ctsServiceUuid), &service->uuid.u) == 0) {
+ if (service != nullptr && ble_uuid_cmp(&ctsServiceUuid.u, &service->uuid.u) == 0) {
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
isDiscovered = true;
ctsStartHandle = service->start_handle;
@@ -72,7 +72,7 @@ int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
return 0;
}
- if (characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*) &currentTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
+ if (characteristic != nullptr && ble_uuid_cmp(&currentTimeCharacteristicUuid.u, &characteristic->uuid.u) == 0) {
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
isCharacteristicDiscovered = true;
currentTimeHandle = characteristic->val_handle;
diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp
index b49be39c..eefb7ec1 100644
--- a/src/components/ble/CurrentTimeService.cpp
+++ b/src/components/ble/CurrentTimeService.cpp
@@ -53,7 +53,7 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
}
CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
- : characteristicDefinition {{.uuid = (ble_uuid_t*) &ctChrUuid,
+ : characteristicDefinition {{.uuid = &ctChrUuid.u,
.access_cb = CTSCallback,
.arg = this,
@@ -62,7 +62,7 @@ CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &ctsUuid,
+ .uuid = &ctsUuid.u,
.characteristics = characteristicDefinition},
{0},
},
diff --git a/src/components/ble/DeviceInformationService.cpp b/src/components/ble/DeviceInformationService.cpp
index cf482079..778d6e35 100644
--- a/src/components/ble/DeviceInformationService.cpp
+++ b/src/components/ble/DeviceInformationService.cpp
@@ -56,37 +56,37 @@ int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16
DeviceInformationService::DeviceInformationService()
: characteristicDefinition {{
- .uuid = (ble_uuid_t*) &manufacturerNameUuid,
+ .uuid = &manufacturerNameUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &modelNumberUuid,
+ .uuid = &modelNumberUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &serialNumberUuid,
+ .uuid = &serialNumberUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &fwRevisionUuid,
+ .uuid = &fwRevisionUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &hwRevisionUuid,
+ .uuid = &hwRevisionUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
},
{
- .uuid = (ble_uuid_t*) &swRevisionUuid,
+ .uuid = &swRevisionUuid.u,
.access_cb = DeviceInformationCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
@@ -95,7 +95,7 @@ DeviceInformationService::DeviceInformationService()
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &deviceInfoUuid,
+ .uuid = &deviceInfoUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
diff --git a/src/components/ble/DfuService.cpp b/src/components/ble/DfuService.cpp
index 4179994d..3d6416fa 100644
--- a/src/components/ble/DfuService.cpp
+++ b/src/components/ble/DfuService.cpp
@@ -33,21 +33,21 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
bleController {bleController},
dfuImage {spiNorFlash},
characteristicDefinition {{
- .uuid = (ble_uuid_t*) &packetCharacteristicUuid,
+ .uuid = &packetCharacteristicUuid.u,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
.val_handle = nullptr,
},
{
- .uuid = (ble_uuid_t*) &controlPointCharacteristicUuid,
+ .uuid = &controlPointCharacteristicUuid.u,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
.val_handle = nullptr,
},
{
- .uuid = (ble_uuid_t*) &revisionCharacteristicUuid,
+ .uuid = &revisionCharacteristicUuid.u,
.access_cb = DfuServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ,
@@ -60,7 +60,7 @@ DfuService::DfuService(Pinetime::System::SystemTask& systemTask,
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &serviceUuid,
+ .uuid = &serviceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
@@ -81,9 +81,9 @@ int DfuService::OnServiceData(uint16_t connectionHandle, uint16_t attributeHandl
xTimerStart(timeoutTimer, 0);
}
- ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &packetCharacteristicUuid, nullptr, &packetCharacteristicHandle);
- ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &controlPointCharacteristicUuid, nullptr, &controlPointCharacteristicHandle);
- ble_gatts_find_chr((ble_uuid_t*) &serviceUuid, (ble_uuid_t*) &revisionCharacteristicUuid, nullptr, &revisionCharacteristicHandle);
+ ble_gatts_find_chr(&serviceUuid.u, &packetCharacteristicUuid.u, nullptr, &packetCharacteristicHandle);
+ ble_gatts_find_chr(&serviceUuid.u, &controlPointCharacteristicUuid.u, nullptr, &controlPointCharacteristicHandle);
+ ble_gatts_find_chr(&serviceUuid.u, &revisionCharacteristicUuid.u, nullptr, &revisionCharacteristicHandle);
if (attributeHandle == packetCharacteristicHandle) {
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
@@ -164,10 +164,10 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
- (uint8_t) (bytesReceived & 0x000000FFu),
- (uint8_t) (bytesReceived >> 8u),
- (uint8_t) (bytesReceived >> 16u),
- (uint8_t) (bytesReceived >> 24u)};
+ (uint8_t)(bytesReceived & 0x000000FFu),
+ (uint8_t)(bytesReceived >> 8u),
+ (uint8_t)(bytesReceived >> 16u),
+ (uint8_t)(bytesReceived >> 24u)};
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
}
@@ -422,9 +422,9 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size,
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
for (uint32_t i = 0; i < size; i++) {
- crc = (uint8_t) (crc >> 8) | (crc << 8);
+ crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= p_data[i];
- crc ^= (uint8_t) (crc & 0xFF) >> 4;
+ crc ^= (uint8_t)(crc & 0xFF) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xFF) << 4) << 1;
}
diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp
index c556566b..5b00f492 100644
--- a/src/components/ble/HeartRateService.cpp
+++ b/src/components/ble/HeartRateService.cpp
@@ -18,7 +18,7 @@ namespace {
HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController)
: system {system},
heartRateController {heartRateController},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &heartRateMeasurementUuid,
+ characteristicDefinition {{.uuid = &heartRateMeasurementUuid.u,
.access_cb = HeartRateServiceServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
@@ -27,7 +27,7 @@ HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Control
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &heartRateServiceUuid,
+ .uuid = &heartRateServiceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp
index 820d3b6e..17ed1a96 100644
--- a/src/components/ble/ImmediateAlertService.cpp
+++ b/src/components/ble/ImmediateAlertService.cpp
@@ -32,7 +32,7 @@ ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& syste
Pinetime::Controllers::NotificationManager& notificationManager)
: systemTask {systemTask},
notificationManager {notificationManager},
- characteristicDefinition {{.uuid = (ble_uuid_t*) &alertLevelUuid,
+ characteristicDefinition {{.uuid = &alertLevelUuid.u,
.access_cb = AlertLevelCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
@@ -41,7 +41,7 @@ ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask& syste
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
- .uuid = (ble_uuid_t*) &immediateAlertServiceUuid,
+ .uuid = &immediateAlertServiceUuid.u,
.characteristics = characteristicDefinition},
{0},
} {
@@ -72,4 +72,4 @@ int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16
}
return 0;
-} \ No newline at end of file
+}
diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp
index e1c20bf1..b49148d2 100644
--- a/src/components/ble/NavigationService.cpp
+++ b/src/components/ble/NavigationService.cpp
@@ -20,54 +20,45 @@
#include "systemtask/SystemTask.h"
-int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
- auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
- return navService->OnCommand(conn_handle, attr_handle, ctxt);
-}
-
-Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
- navUuid.value[14] = navId[0];
- navUuid.value[15] = navId[1];
+namespace {
+ // 0001yyxx-78fc-48fe-8e23-433b3a1942d0
+ constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
+ return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
+ .value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x01, 0x00}};
+ }
- navFlagCharUuid.value[12] = navFlagCharId[0];
- navFlagCharUuid.value[13] = navFlagCharId[1];
- navFlagCharUuid.value[14] = navId[0];
- navFlagCharUuid.value[15] = navId[1];
+ // 00010000-78fc-48fe-8e23-433b3a1942d0
+ constexpr ble_uuid128_t BaseUuid() {
+ return CharUuid(0x00, 0x00);
+ }
- navNarrativeCharUuid.value[12] = navNarrativeCharId[0];
- navNarrativeCharUuid.value[13] = navNarrativeCharId[1];
- navNarrativeCharUuid.value[14] = navId[0];
- navNarrativeCharUuid.value[15] = navId[1];
+ constexpr ble_uuid128_t navUuid {BaseUuid()};
- navManDistCharUuid.value[12] = navManDistCharId[0];
- navManDistCharUuid.value[13] = navManDistCharId[1];
- navManDistCharUuid.value[14] = navId[0];
- navManDistCharUuid.value[15] = navId[1];
+ constexpr ble_uuid128_t navFlagCharUuid {CharUuid(0x01, 0x00)};
+ constexpr ble_uuid128_t navNarrativeCharUuid {CharUuid(0x02, 0x00)};
+ constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)};
+ constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)};
- navProgressCharUuid.value[12] = navProgressCharId[0];
- navProgressCharUuid.value[13] = navProgressCharId[1];
- navProgressCharUuid.value[14] = navId[0];
- navProgressCharUuid.value[15] = navId[1];
+ int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
+ auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg);
+ return navService->OnCommand(conn_handle, attr_handle, ctxt);
+ }
+} // namespace
+Pinetime::Controllers::NavigationService::NavigationService(Pinetime::System::SystemTask& system) : m_system(system) {
characteristicDefinition[0] = {
- .uuid = (ble_uuid_t*) (&navFlagCharUuid), .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
-
- characteristicDefinition[1] = {.uuid = (ble_uuid_t*) (&navNarrativeCharUuid),
- .access_cb = NAVCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
- characteristicDefinition[2] = {.uuid = (ble_uuid_t*) (&navManDistCharUuid),
- .access_cb = NAVCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
- characteristicDefinition[3] = {.uuid = (ble_uuid_t*) (&navProgressCharUuid),
- .access_cb = NAVCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+ .uuid = &navFlagCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+
+ characteristicDefinition[1] = {
+ .uuid = &navNarrativeCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+ characteristicDefinition[2] = {
+ .uuid = &navManDistCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
+ characteristicDefinition[3] = {
+ .uuid = &navProgressCharUuid.u, .access_cb = NAVCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[4] = {0};
- serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &navUuid, .characteristics = characteristicDefinition};
+ serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &navUuid.u, .characteristics = characteristicDefinition};
serviceDefinition[1] = {0};
m_progress = 0;
@@ -90,13 +81,13 @@ int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, ui
data[notifSize] = '\0';
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
char* s = (char*) &data[0];
- if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navFlagCharUuid) == 0) {
+ if (ble_uuid_cmp(ctxt->chr->uuid, &navFlagCharUuid.u) == 0) {
m_flag = s;
- } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navNarrativeCharUuid) == 0) {
+ } else if (ble_uuid_cmp(ctxt->chr->uuid, &navNarrativeCharUuid.u) == 0) {
m_narrative = s;
- } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navManDistCharUuid) == 0) {
+ } else if (ble_uuid_cmp(ctxt->chr->uuid, &navManDistCharUuid.u) == 0) {
m_manDist = s;
- } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &navProgressCharUuid) == 0) {
+ } else if (ble_uuid_cmp(ctxt->chr->uuid, &navProgressCharUuid.u) == 0) {
m_progress = data[0];
}
}
diff --git a/src/components/ble/NavigationService.h b/src/components/ble/NavigationService.h
index 5aab263c..c0c77f35 100644
--- a/src/components/ble/NavigationService.h
+++ b/src/components/ble/NavigationService.h
@@ -26,10 +26,6 @@
#undef max
#undef min
-// c7e60000-78fc-48fe-8e23-433b3a1942d0
-#define NAVIGATION_SERVICE_UUID_BASE \
- { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
-
namespace Pinetime {
namespace System {
class SystemTask;
@@ -53,19 +49,6 @@ namespace Pinetime {
int getProgress();
private:
- static constexpr uint8_t navId[2] = {0x01, 0x00};
- static constexpr uint8_t navFlagCharId[2] = {0x01, 0x00};
- static constexpr uint8_t navNarrativeCharId[2] = {0x02, 0x00};
- static constexpr uint8_t navManDistCharId[2] = {0x03, 0x00};
- static constexpr uint8_t navProgressCharId[2] = {0x04, 0x00};
-
- ble_uuid128_t navUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
-
- ble_uuid128_t navFlagCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
- ble_uuid128_t navNarrativeCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
- ble_uuid128_t navManDistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
- ble_uuid128_t navProgressCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = NAVIGATION_SERVICE_UUID_BASE};
-
struct ble_gatt_chr_def characteristicDefinition[5];
struct ble_gatt_svc_def serviceDefinition[2];
diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp
index b1b0e6b2..7ffed300 100644
--- a/src/components/ble/NotificationManager.cpp
+++ b/src/components/ble/NotificationManager.cpp
@@ -79,14 +79,6 @@ bool NotificationManager::AreNewNotificationsAvailable() {
return newNotification;
}
-bool NotificationManager::IsVibrationEnabled() {
- return vibrationEnabled;
-}
-
-void NotificationManager::ToggleVibrations() {
- vibrationEnabled = !vibrationEnabled;
-}
-
bool NotificationManager::ClearNewNotificationFlag() {
return newNotification.exchange(false);
}
diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h
index d4072cc2..40f174ea 100644
--- a/src/components/ble/NotificationManager.h
+++ b/src/components/ble/NotificationManager.h
@@ -44,8 +44,6 @@ namespace Pinetime {
Notification GetPrevious(Notification::Id id);
bool ClearNewNotificationFlag();
bool AreNewNotificationsAvailable();
- bool IsVibrationEnabled();
- void ToggleVibrations();
static constexpr size_t MaximumMessageSize() {
return MessageSize;
@@ -60,7 +58,6 @@ namespace Pinetime {
uint8_t writeIndex = 0;
bool empty = true;
std::atomic<bool> newNotification {false};
- bool vibrationEnabled = true;
};
}
-} \ No newline at end of file
+}
diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp
index d6aa83c8..e9c5d870 100644
--- a/src/components/datetime/DateTimeController.cpp
+++ b/src/components/datetime/DateTimeController.cpp
@@ -5,6 +5,17 @@
using namespace Pinetime::Controllers;
+namespace {
+ char const* DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
+ char const* MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
+ char const* MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+}
+
+void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
+ this->currentDateTime = t;
+ UpdateTime(previousSystickCounter); // Update internal state without updating the time
+}
+
void DateTime::SetTime(
uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
std::tm tm = {
@@ -67,7 +78,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
// Notify new day to SystemTask
if (hour == 0 and not isMidnightAlreadyNotified) {
isMidnightAlreadyNotified = true;
- if(systemTask != nullptr)
+ if (systemTask != nullptr)
systemTask->PushMessage(System::Messages::OnNewDay);
} else if (hour != 0) {
isMidnightAlreadyNotified = false;
@@ -75,48 +86,18 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
}
const char* DateTime::MonthShortToString() {
- return DateTime::MonthsString[static_cast<uint8_t>(month)];
-}
-
-const char* DateTime::MonthShortToStringLow() {
- return DateTime::MonthsStringLow[static_cast<uint8_t>(month)];
-}
-
-const char* DateTime::MonthsToStringLow() {
- return DateTime::MonthsLow[static_cast<uint8_t>(month)];
-}
-
-const char* DateTime::DayOfWeekToString() {
- return DateTime::DaysString[static_cast<uint8_t>(dayOfWeek)];
+ return MonthsString[static_cast<uint8_t>(month)];
}
const char* DateTime::DayOfWeekShortToString() {
- return DateTime::DaysStringShort[static_cast<uint8_t>(dayOfWeek)];
-}
-
-const char* DateTime::DayOfWeekToStringLow() {
- return DateTime::DaysStringLow[static_cast<uint8_t>(dayOfWeek)];
+ return DaysStringShort[static_cast<uint8_t>(dayOfWeek)];
}
-const char* DateTime::DayOfWeekShortToStringLow() {
- return DateTime::DaysStringShortLow[static_cast<uint8_t>(dayOfWeek)];
+const char* DateTime::MonthShortToStringLow(Months month) {
+ return MonthsStringLow[static_cast<uint8_t>(month)];
}
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
this->systemTask = systemTask;
}
-char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
-
-char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
-
-char const* DateTime::DaysStringShort[] = {"--", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
-
-char const* DateTime::DaysString[] = {"--", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"};
-
-char const* DateTime::MonthsString[] = {"--", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
-
-char const* DateTime::MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
-char const* DateTime::MonthsLow[] = {
- "--", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; \ No newline at end of file
diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h
index 265d6e9d..77ed68e8 100644
--- a/src/components/datetime/DateTimeController.h
+++ b/src/components/datetime/DateTimeController.h
@@ -59,12 +59,8 @@ namespace Pinetime {
}
const char* MonthShortToString();
- const char* MonthShortToStringLow();
- const char* MonthsToStringLow();
- const char* DayOfWeekToString();
const char* DayOfWeekShortToString();
- const char* DayOfWeekToStringLow();
- const char* DayOfWeekShortToStringLow();
+ static const char* MonthShortToStringLow(Months month);
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
return currentDateTime;
@@ -74,6 +70,7 @@ namespace Pinetime {
}
void Register(System::SystemTask* systemTask);
+ void SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t);
private:
uint16_t year = 0;
@@ -90,14 +87,6 @@ namespace Pinetime {
bool isMidnightAlreadyNotified = false;
System::SystemTask* systemTask = nullptr;
-
- static char const* DaysString[];
- static char const* DaysStringShort[];
- static char const* DaysStringLow[];
- static char const* DaysStringShortLow[];
- static char const* MonthsString[];
- static char const* MonthsStringLow[];
- static char const* MonthsLow[];
};
}
-} \ No newline at end of file
+}
diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h
index 1f2eb7e0..75ba16c8 100644
--- a/src/components/fs/FS.h
+++ b/src/components/fs/FS.h
@@ -53,7 +53,7 @@ namespace Pinetime {
*
*/
static constexpr size_t startAddress = 0x0B4000;
- static constexpr size_t size = 0x3C0000;
+ static constexpr size_t size = 0x34C000;
static constexpr size_t blockSize = 4096;
bool resourcesValid = false;
diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp
index 42057a86..f596c718 100644
--- a/src/components/motor/MotorController.cpp
+++ b/src/components/motor/MotorController.cpp
@@ -9,9 +9,6 @@ APP_TIMER_DEF(longVibTimer);
using namespace Pinetime::Controllers;
-MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} {
-}
-
void MotorController::Init() {
nrf_gpio_cfg_output(PinMap::Motor);
nrf_gpio_pin_set(PinMap::Motor);
@@ -27,18 +24,11 @@ void MotorController::Ring(void* p_context) {
}
void MotorController::RunForDuration(uint8_t motorDuration) {
- if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
- return;
- }
-
nrf_gpio_pin_clear(PinMap::Motor);
app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr);
}
void MotorController::StartRinging() {
- if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) {
- return;
- }
Ring(this);
app_timer_start(longVibTimer, APP_TIMER_TICKS(1000), this);
}
diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h
index cf78088e..c9326d57 100644
--- a/src/components/motor/MotorController.h
+++ b/src/components/motor/MotorController.h
@@ -1,14 +1,14 @@
#pragma once
#include <cstdint>
-#include "components/settings/Settings.h"
namespace Pinetime {
namespace Controllers {
class MotorController {
public:
- MotorController(Controllers::Settings& settingsController);
+ MotorController() = default;
+
void Init();
void RunForDuration(uint8_t motorDuration);
void StartRinging();
@@ -16,7 +16,6 @@ namespace Pinetime {
private:
static void Ring(void* p_context);
- Controllers::Settings& settingsController;
static void StopMotor(void* p_context);
};
}
diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h
index a54ba976..871ff3b6 100644
--- a/src/components/settings/Settings.h
+++ b/src/components/settings/Settings.h
@@ -11,7 +11,7 @@ namespace Pinetime {
class Settings {
public:
enum class ClockType : uint8_t { H24, H12 };
- enum class Vibration : uint8_t { ON, OFF };
+ enum class Notification : uint8_t { ON, OFF };
enum class WakeUpMode : uint8_t {
SingleTap = 0,
DoubleTap = 1,
@@ -93,14 +93,14 @@ namespace Pinetime {
return settings.clockType;
};
- void SetVibrationStatus(Vibration status) {
- if (status != settings.vibrationStatus) {
+ void SetNotificationStatus(Notification status) {
+ if (status != settings.notificationStatus) {
settingsChanged = true;
}
- settings.vibrationStatus = status;
+ settings.notificationStatus = status;
};
- Vibration GetVibrationStatus() const {
- return settings.vibrationStatus;
+ Notification GetNotificationStatus() const {
+ return settings.notificationStatus;
};
void SetScreenTimeOut(uint32_t timeout) {
@@ -170,7 +170,7 @@ namespace Pinetime {
uint32_t screenTimeOut = 15000;
ClockType clockType = ClockType::H24;
- Vibration vibrationStatus = Vibration::ON;
+ Notification notificationStatus = Notification::ON;
uint8_t clockFace = 0;
diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h
index dd51fdb4..d340efee 100644
--- a/src/displayapp/Apps.h
+++ b/src/displayapp/Apps.h
@@ -12,6 +12,7 @@ namespace Pinetime {
NotificationsPreview,
Notifications,
Timer,
+ Alarm,
FlashLight,
BatteryInfo,
Music,
@@ -31,7 +32,10 @@ namespace Pinetime {
SettingDisplay,
SettingWakeUp,
SettingSteps,
- SettingPineTimeStyle
+ SettingPineTimeStyle,
+ SettingSetDate,
+ SettingSetTime,
+ Error,
};
}
}
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index 5e74baa0..abe5851e 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -3,6 +3,7 @@
#include <displayapp/screens/HeartRate.h>
#include <displayapp/screens/Motion.h>
#include <displayapp/screens/Timer.h>
+#include <displayapp/screens/Alarm.h>
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/datetime/DateTimeController.h"
@@ -28,6 +29,7 @@
#include "displayapp/screens/FlashLight.h"
#include "displayapp/screens/BatteryInfo.h"
#include "displayapp/screens/Steps.h"
+#include "displayapp/screens/Error.h"
#include "drivers/Cst816s.h"
#include "drivers/St7789.h"
@@ -43,6 +45,8 @@
#include "displayapp/screens/settings/SettingDisplay.h"
#include "displayapp/screens/settings/SettingSteps.h"
#include "displayapp/screens/settings/SettingPineTimeStyle.h"
+#include "displayapp/screens/settings/SettingSetDate.h"
+#include "displayapp/screens/settings/SettingSetTime.h"
#include "libs/lv_conf.h"
@@ -90,6 +94,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler)
: lcd {lcd},
lvgl {lvgl},
@@ -104,14 +109,20 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
motorController {motorController},
motionController {motionController},
timerController {timerController},
+ alarmController {alarmController},
touchHandler {touchHandler} {
}
-void DisplayApp::Start() {
+void DisplayApp::Start(System::BootErrors error) {
msgQueue = xQueueCreate(queueSize, itemSize);
- // Start clock when smartwatch boots
- LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
+ bootError = error;
+
+ if (error == System::BootErrors::TouchController) {
+ LoadApp(Apps::Error, DisplayApp::FullRefreshDirections::None);
+ } else {
+ LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
+ }
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) {
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
@@ -138,19 +149,15 @@ void DisplayApp::InitHw() {
void DisplayApp::Refresh() {
TickType_t queueTimeout;
- TickType_t delta;
switch (state) {
case States::Idle:
- IdleState();
queueTimeout = portMAX_DELAY;
break;
case States::Running:
- RunningState();
- delta = xTaskGetTickCount() - lastWakeTime;
- if (delta > LV_DISP_DEF_REFR_PERIOD) {
- delta = LV_DISP_DEF_REFR_PERIOD;
+ if (!currentScreen->IsRunning()) {
+ LoadApp(returnToApp, returnDirection);
}
- queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta;
+ queueTimeout = lv_task_handler();
break;
default:
queueTimeout = portMAX_DELAY;
@@ -158,9 +165,7 @@ void DisplayApp::Refresh() {
}
Messages msg;
- bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout);
- lastWakeTime = xTaskGetTickCount();
- if (messageReceived) {
+ if (xQueueReceive(msgQueue, &msg, queueTimeout)) {
switch (msg) {
case Messages::DimScreen:
// Backup brightness is the brightness to return to after dimming or sleeping
@@ -202,6 +207,13 @@ void DisplayApp::Refresh() {
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
}
break;
+ case Messages::AlarmTriggered:
+ if (currentApp == Apps::Alarm) {
+ auto* alarm = static_cast<Screens::Alarm*>(currentScreen.get());
+ alarm->SetAlerting();
+ } else {
+ LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None);
+ }
case Messages::TouchEvent: {
if (state != States::Running) {
break;
@@ -269,13 +281,6 @@ void DisplayApp::Refresh() {
}
}
-void DisplayApp::RunningState() {
- if (!currentScreen->IsRunning()) {
- LoadApp(returnToApp, returnDirection);
- }
- lv_task_handler();
-}
-
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
nextApp = app;
nextDirection = direction;
@@ -312,6 +317,11 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
motionController);
break;
+ case Apps::Error:
+ currentScreen = std::make_unique<Screens::Error>(this, bootError);
+ ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
+ break;
+
case Apps::FirmwareValidation:
currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
@@ -334,6 +344,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
case Apps::Timer:
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
break;
+ case Apps::Alarm:
+ currentScreen = std::make_unique<Screens::Alarm>(this, alarmController);
+ break;
// Settings
case Apps::QuickSettings:
@@ -365,6 +378,14 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
+ case Apps::SettingSetDate:
+ currentScreen = std::make_unique<Screens::SettingSetDate>(this, dateTimeController);
+ ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
+ case Apps::SettingSetTime:
+ currentScreen = std::make_unique<Screens::SettingSetTime>(this, dateTimeController);
+ ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
case Apps::SettingPineTimeStyle:
currentScreen = std::make_unique<Screens::SettingPineTimeStyle>(this, settingsController);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
@@ -375,12 +396,12 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
break;
case Apps::SysInfo:
currentScreen = std::make_unique<Screens::SystemInfo>(
- this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController);
+ this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController, touchPanel);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::FlashLight:
currentScreen = std::make_unique<Screens::FlashLight>(this, *systemTask, brightnessController);
- ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
+ ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::StopWatch:
currentScreen = std::make_unique<Screens::StopWatch>(this, *systemTask);
@@ -417,9 +438,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentApp = app;
}
-void DisplayApp::IdleState() {
-}
-
void DisplayApp::PushMessage(Messages msg) {
if (in_isr()) {
BaseType_t xHigherPriorityTaskWoken;
diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h
index 96951d1c..a87cab0b 100644
--- a/src/displayapp/DisplayApp.h
+++ b/src/displayapp/DisplayApp.h
@@ -14,8 +14,11 @@
#include "components/settings/Settings.h"
#include "displayapp/screens/Screen.h"
#include "components/timer/TimerController.h"
+#include "components/alarm/AlarmController.h"
#include "touchhandler/TouchHandler.h"
+
#include "Messages.h"
+#include "BootErrors.h"
namespace Pinetime {
@@ -57,8 +60,9 @@ namespace Pinetime {
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler);
- void Start();
+ void Start(System::BootErrors error);
void PushMessage(Display::Messages msg);
void StartApp(Apps app, DisplayApp::FullRefreshDirections direction);
@@ -82,6 +86,7 @@ namespace Pinetime {
Pinetime::Controllers::MotorController& motorController;
Pinetime::Controllers::MotionController& motionController;
Pinetime::Controllers::TimerController& timerController;
+ Pinetime::Controllers::AlarmController& alarmController;
Pinetime::Controllers::TouchHandler& touchHandler;
Pinetime::Controllers::FirmwareValidator validator;
@@ -103,8 +108,6 @@ namespace Pinetime {
TouchEvents returnTouchEvent = TouchEvents::None;
TouchEvents GetGesture();
- void RunningState();
- void IdleState();
static void Process(void* instance);
void InitHw();
void Refresh();
@@ -114,7 +117,7 @@ namespace Pinetime {
Apps nextApp = Apps::None;
DisplayApp::FullRefreshDirections nextDirection;
- TickType_t lastWakeTime;
+ System::BootErrors bootError;
};
}
}
diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp
index 7a202629..a42d81a2 100644
--- a/src/displayapp/DisplayAppRecovery.cpp
+++ b/src/displayapp/DisplayAppRecovery.cpp
@@ -22,6 +22,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler)
: lcd {lcd}, bleController {bleController} {
diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h
index 4184ea49..9f5fb130 100644
--- a/src/displayapp/DisplayAppRecovery.h
+++ b/src/displayapp/DisplayAppRecovery.h
@@ -10,6 +10,7 @@
#include <date/date.h>
#include <drivers/Watchdog.h>
#include <components/motor/MotorController.h>
+#include <BootErrors.h>
#include "TouchEvents.h"
#include "Apps.h"
#include "Messages.h"
@@ -32,6 +33,7 @@ namespace Pinetime {
class TouchHandler;
class MotorController;
class TimerController;
+ class AlarmController;
}
namespace System {
@@ -54,8 +56,10 @@ namespace Pinetime {
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
Pinetime::Controllers::TimerController& timerController,
+ Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::TouchHandler& touchHandler);
void Start();
+ void Start(Pinetime::System::BootErrors){ Start(); };
void PushMessage(Pinetime::Applications::Display::Messages msg);
void Register(Pinetime::System::SystemTask* systemTask);
diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h
index 8e4884db..d48b646f 100644
--- a/src/displayapp/Messages.h
+++ b/src/displayapp/Messages.h
@@ -14,7 +14,8 @@ namespace Pinetime {
BleFirmwareUpdateStarted,
UpdateTimeOut,
DimScreen,
- RestoreBrightness
+ RestoreBrightness,
+ AlarmTriggered
};
}
}
diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp
new file mode 100644
index 00000000..6b45a36e
--- /dev/null
+++ b/src/displayapp/screens/Alarm.cpp
@@ -0,0 +1,265 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "Alarm.h"
+#include "Screen.h"
+#include "Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+using Pinetime::Controllers::AlarmController;
+
+static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
+ Alarm* screen = static_cast<Alarm*>(obj->user_data);
+ screen->OnButtonEvent(obj, event);
+}
+
+Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController)
+ : Screen(app), running {true}, alarmController {alarmController} {
+
+ time = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
+ lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+
+ alarmHours = alarmController.Hours();
+ alarmMinutes = alarmController.Minutes();
+ lv_label_set_text_fmt(time, "%02lu:%02lu", alarmHours, alarmMinutes);
+
+ lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25);
+
+ btnHoursUp = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursUp->user_data = this;
+ lv_obj_set_event_cb(btnHoursUp, btnEventHandler);
+ lv_obj_set_size(btnHoursUp, 60, 40);
+ lv_obj_align(btnHoursUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -85);
+ txtHrUp = lv_label_create(btnHoursUp, nullptr);
+ lv_label_set_text_static(txtHrUp, "+");
+
+ btnHoursDown = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursDown->user_data = this;
+ lv_obj_set_event_cb(btnHoursDown, btnEventHandler);
+ lv_obj_set_size(btnHoursDown, 60, 40);
+ lv_obj_align(btnHoursDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, 35);
+ txtHrDown = lv_label_create(btnHoursDown, nullptr);
+ lv_label_set_text_static(txtHrDown, "-");
+
+ btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesUp->user_data = this;
+ lv_obj_set_event_cb(btnMinutesUp, btnEventHandler);
+ lv_obj_set_size(btnMinutesUp, 60, 40);
+ lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, -85);
+ txtMinUp = lv_label_create(btnMinutesUp, nullptr);
+ lv_label_set_text_static(txtMinUp, "+");
+
+ btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesDown->user_data = this;
+ lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
+ lv_obj_set_size(btnMinutesDown, 60, 40);
+ lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, 35);
+ txtMinDown = lv_label_create(btnMinutesDown, nullptr);
+ lv_label_set_text_static(txtMinDown, "-");
+
+ btnEnable = lv_btn_create(lv_scr_act(), nullptr);
+ btnEnable->user_data = this;
+ lv_obj_set_event_cb(btnEnable, btnEventHandler);
+ lv_obj_set_size(btnEnable, 115, 50);
+ lv_obj_align(btnEnable, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
+ txtEnable = lv_label_create(btnEnable, nullptr);
+ SetEnableButtonState();
+
+ btnRecur = lv_btn_create(lv_scr_act(), nullptr);
+ btnRecur->user_data = this;
+ lv_obj_set_event_cb(btnRecur, btnEventHandler);
+ lv_obj_set_size(btnRecur, 115, 50);
+ lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
+ txtRecur = lv_label_create(btnRecur, nullptr);
+ SetRecurButtonState();
+
+ btnInfo = lv_btn_create(lv_scr_act(), nullptr);
+ btnInfo->user_data = this;
+ lv_obj_set_event_cb(btnInfo, btnEventHandler);
+ lv_obj_set_size(btnInfo, 50, 40);
+ lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85);
+ txtInfo = lv_label_create(btnInfo, nullptr);
+ lv_label_set_text_static(txtInfo, "i");
+}
+
+Alarm::~Alarm() {
+ lv_obj_clean(lv_scr_act());
+}
+
+void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
+ using Pinetime::Controllers::AlarmController;
+ if (event == LV_EVENT_CLICKED) {
+ if (obj == btnEnable) {
+ if (alarmController.State() == AlarmController::AlarmState::Alerting) {
+ alarmController.StopAlerting();
+ } else if (alarmController.State() == AlarmController::AlarmState::Set) {
+ alarmController.DisableAlarm();
+ } else {
+ alarmController.ScheduleAlarm();
+ }
+ SetEnableButtonState();
+ return;
+ }
+ if (obj == btnInfo) {
+ ShowInfo();
+ return;
+ }
+ if (obj == btnMessage) {
+ HideInfo();
+ return;
+ }
+ // If any other button was pressed, disable the alarm
+ // this is to make it clear that the alarm won't be set until it is turned back on
+ if (alarmController.State() == AlarmController::AlarmState::Set) {
+ alarmController.DisableAlarm();
+ SetEnableButtonState();
+ }
+ if (obj == btnMinutesUp) {
+ if (alarmMinutes >= 59) {
+ alarmMinutes = 0;
+ } else {
+ alarmMinutes++;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnMinutesDown) {
+ if (alarmMinutes == 0) {
+ alarmMinutes = 59;
+ } else {
+ alarmMinutes--;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnHoursUp) {
+ if (alarmHours >= 23) {
+ alarmHours = 0;
+ } else {
+ alarmHours++;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnHoursDown) {
+ if (alarmHours == 0) {
+ alarmHours = 23;
+ } else {
+ alarmHours--;
+ }
+ UpdateAlarmTime();
+ return;
+ }
+ if (obj == btnRecur) {
+ ToggleRecurrence();
+ }
+ }
+}
+
+bool Alarm::OnButtonPushed() {
+ if (txtMessage != nullptr && btnMessage != nullptr) {
+ HideInfo();
+ return true;
+ }
+ return false;
+}
+
+void Alarm::UpdateAlarmTime() {
+ lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes);
+ alarmController.SetAlarmTime(alarmHours, alarmMinutes);
+}
+
+void Alarm::SetAlerting() {
+ SetEnableButtonState();
+}
+
+void Alarm::SetEnableButtonState() {
+ switch (alarmController.State()) {
+ case AlarmController::AlarmState::Set:
+ lv_label_set_text(txtEnable, "ON");
+ lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ break;
+ case AlarmController::AlarmState::Not_Set:
+ lv_label_set_text(txtEnable, "OFF");
+ lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+ break;
+ case AlarmController::AlarmState::Alerting:
+ lv_label_set_text(txtEnable, Symbols::stop);
+ lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
+ }
+}
+
+void Alarm::ShowInfo() {
+ btnMessage = lv_btn_create(lv_scr_act(), nullptr);
+ btnMessage->user_data = this;
+ lv_obj_set_event_cb(btnMessage, btnEventHandler);
+ lv_obj_set_height(btnMessage, 200);
+ lv_obj_set_width(btnMessage, 150);
+ lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+ txtMessage = lv_label_create(btnMessage, nullptr);
+ lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
+
+ if (alarmController.State() == AlarmController::AlarmState::Set) {
+ auto timeToAlarm = alarmController.SecondsToAlarm();
+
+ auto daysToAlarm = timeToAlarm / 86400;
+ auto hrsToAlarm = (timeToAlarm % 86400) / 3600;
+ auto minToAlarm = (timeToAlarm % 3600) / 60;
+ auto secToAlarm = timeToAlarm % 60;
+
+ lv_label_set_text_fmt(
+ txtMessage, "Time to\nalarm:\n%2d Days\n%2d Hours\n%2d Minutes\n%2d Seconds", daysToAlarm, hrsToAlarm, minToAlarm, secToAlarm);
+ } else {
+ lv_label_set_text(txtMessage, "Alarm\nis not\nset.");
+ }
+}
+
+void Alarm::HideInfo() {
+ lv_obj_del(btnMessage);
+ txtMessage = nullptr;
+ btnMessage = nullptr;
+}
+
+void Alarm::SetRecurButtonState() {
+ using Pinetime::Controllers::AlarmController;
+ switch (alarmController.Recurrence()) {
+ case AlarmController::RecurType::None:
+ lv_label_set_text(txtRecur, "ONCE");
+ break;
+ case AlarmController::RecurType::Daily:
+ lv_label_set_text(txtRecur, "DAILY");
+ break;
+ case AlarmController::RecurType::Weekdays:
+ lv_label_set_text(txtRecur, "MON-FRI");
+ }
+}
+
+void Alarm::ToggleRecurrence() {
+ using Pinetime::Controllers::AlarmController;
+ switch (alarmController.Recurrence()) {
+ case AlarmController::RecurType::None:
+ alarmController.SetRecurrence(AlarmController::RecurType::Daily);
+ break;
+ case AlarmController::RecurType::Daily:
+ alarmController.SetRecurrence(AlarmController::RecurType::Weekdays);
+ break;
+ case AlarmController::RecurType::Weekdays:
+ alarmController.SetRecurrence(AlarmController::RecurType::None);
+ }
+ SetRecurButtonState();
+}
diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h
new file mode 100644
index 00000000..32a14d2f
--- /dev/null
+++ b/src/displayapp/screens/Alarm.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2021 mruss77, Florian
+
+ This file is part of InfiniTime.
+
+ InfiniTime is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "Screen.h"
+#include "systemtask/SystemTask.h"
+#include "../LittleVgl.h"
+#include "components/alarm/AlarmController.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Alarm : public Screen {
+ public:
+ Alarm(DisplayApp* app, Controllers::AlarmController& alarmController);
+ ~Alarm() override;
+ void SetAlerting();
+ void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
+ bool OnButtonPushed() override;
+
+ private:
+ bool running;
+ uint8_t alarmHours;
+ uint8_t alarmMinutes;
+ Controllers::AlarmController& alarmController;
+
+ lv_obj_t *time, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown,
+ *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnMessage, *txtMessage, *btnInfo, *txtInfo;
+
+ enum class EnableButtonState { On, Off, Alerting };
+ void SetEnableButtonState();
+ void SetRecurButtonState();
+ void SetAlarm();
+ void ShowInfo();
+ void HideInfo();
+ void ToggleRecurrence();
+ void UpdateAlarmTime();
+ };
+ };
+ };
+}
diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp
index 6e7bbb74..5c582f60 100644
--- a/src/displayapp/screens/ApplicationList.cpp
+++ b/src/displayapp/screens/ApplicationList.cpp
@@ -58,7 +58,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
{"2", Apps::Twos},
{Symbols::chartLine, Apps::Motion},
{Symbols::drum, Apps::Metronome},
- {"", Apps::None},
+ {Symbols::clock, Apps::Alarm},
}};
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp
index ad9af153..44ea7f51 100644
--- a/src/displayapp/screens/BatteryInfo.cpp
+++ b/src/displayapp/screens/BatteryInfo.cpp
@@ -58,7 +58,7 @@ void BatteryInfo::Refresh() {
batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage();
- if (batteryController.IsCharging() and batteryPercent < 100) {
+ if (batteryController.IsCharging()) {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text_static(status, "Charging");
} else if (batteryPercent == 100) {
diff --git a/src/displayapp/screens/Error.cpp b/src/displayapp/screens/Error.cpp
new file mode 100644
index 00000000..75946aba
--- /dev/null
+++ b/src/displayapp/screens/Error.cpp
@@ -0,0 +1,50 @@
+#include "Error.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ void ButtonEventCallback(lv_obj_t* obj, lv_event_t /*event*/) {
+ auto* errorScreen = static_cast<Error*>(obj->user_data);
+ errorScreen->ButtonEventHandler();
+ }
+}
+
+Error::Error(Pinetime::Applications::DisplayApp* app, System::BootErrors error)
+ : Screen(app) {
+
+ lv_obj_t* warningLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(warningLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+ lv_label_set_text_static(warningLabel, "Warning");
+ lv_obj_align(warningLabel, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0);
+
+ lv_obj_t* causeLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(causeLabel, LV_LABEL_LONG_BREAK);
+ lv_obj_set_width(causeLabel, LV_HOR_RES);
+ lv_obj_align(causeLabel, warningLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
+
+ if (error == System::BootErrors::TouchController) {
+ lv_label_set_text_static(causeLabel, "Touch controller error detected.");
+ }
+
+ lv_obj_t* tipLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(tipLabel, LV_LABEL_LONG_BREAK);
+ lv_obj_set_width(tipLabel, LV_HOR_RES);
+ lv_label_set_text_static(tipLabel, "If you encounter problems and your device is under warranty, contact the devices seller.");
+ lv_obj_align(tipLabel, causeLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
+
+ btnOk = lv_btn_create(lv_scr_act(), nullptr);
+ btnOk->user_data = this;
+ lv_obj_set_event_cb(btnOk, ButtonEventCallback);
+ lv_obj_set_size(btnOk, LV_HOR_RES, 50);
+ lv_obj_align(btnOk, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_obj_set_style_local_value_str(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Proceed");
+ lv_obj_set_style_local_bg_color(btnOk, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+}
+
+void Error::ButtonEventHandler() {
+ running = false;
+}
+
+Error::~Error() {
+ lv_obj_clean(lv_scr_act());
+}
diff --git a/src/displayapp/screens/Error.h b/src/displayapp/screens/Error.h
new file mode 100644
index 00000000..20dde7ee
--- /dev/null
+++ b/src/displayapp/screens/Error.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "Screen.h"
+#include "BootErrors.h"
+#include <lvgl/lvgl.h>
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Error : public Screen {
+ public:
+ Error(DisplayApp* app, System::BootErrors error);
+ ~Error() override;
+
+ void ButtonEventHandler();
+ private:
+ lv_obj_t* btnOk;
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/FlashLight.cpp b/src/displayapp/screens/FlashLight.cpp
index 4bc5b558..dcb31a7f 100644
--- a/src/displayapp/screens/FlashLight.cpp
+++ b/src/displayapp/screens/FlashLight.cpp
@@ -5,30 +5,41 @@
using namespace Pinetime::Applications::Screens;
namespace {
- static void event_handler(lv_obj_t* obj, lv_event_t event) {
- FlashLight* screen = static_cast<FlashLight*>(obj->user_data);
+ void event_handler(lv_obj_t* obj, lv_event_t event) {
+ auto* screen = static_cast<FlashLight*>(obj->user_data);
screen->OnClickEvent(obj, event);
}
}
FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
System::SystemTask& systemTask,
- Controllers::BrightnessController& brightness)
+ Controllers::BrightnessController& brightnessController)
: Screen(app),
systemTask {systemTask},
- brightness {brightness}
+ brightnessController {brightnessController}
{
- brightness.Backup();
- brightness.Set(Controllers::BrightnessController::Levels::High);
- // Set the background
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
+ brightnessController.Backup();
- flashLight = lv_label_create(lv_scr_act(), NULL);
- lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ brightnessLevel = brightnessController.Level();
+
+ flashLight = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
lv_label_set_text_static(flashLight, Symbols::highlight);
- lv_obj_align(flashLight, NULL, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_align(flashLight, nullptr, LV_ALIGN_CENTER, 0, 0);
+
+ for (auto & i : indicators) {
+ i = lv_obj_create(lv_scr_act(), nullptr);
+ lv_obj_set_size(i, 15, 10);
+ lv_obj_set_style_local_border_width(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 2);
+ }
+
+ lv_obj_align(indicators[1], flashLight, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
+ lv_obj_align(indicators[0], indicators[1], LV_ALIGN_OUT_LEFT_MID, -8, 0);
+ lv_obj_align(indicators[2], indicators[1], LV_ALIGN_OUT_RIGHT_MID, 8, 0);
+
+ SetIndicators();
+ SetColors();
backgroundAction = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundAction, LV_LABEL_LONG_CROP);
@@ -44,27 +55,80 @@ FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act());
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- brightness.Restore();
+ lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ brightnessController.Restore();
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
-void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
- if (obj == backgroundAction) {
- if (event == LV_EVENT_CLICKED) {
- isOn = !isOn;
-
- if (isOn) {
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
- lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- } else {
- lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
- }
+void FlashLight::SetColors() {
+ if (isOn) {
+ lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+ for (auto & i : indicators) {
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_WHITE);
+ lv_obj_set_style_local_border_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
}
+ } else {
+ lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ for (auto & i : indicators) {
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_BLACK);
+ lv_obj_set_style_local_border_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ }
+ }
+}
+
+void FlashLight::SetIndicators() {
+ using namespace Pinetime::Controllers;
+
+ if (brightnessLevel == BrightnessController::Levels::High) {
+ lv_obj_set_state(indicators[1], LV_STATE_DEFAULT);
+ lv_obj_set_state(indicators[2], LV_STATE_DEFAULT);
+ } else if (brightnessLevel == BrightnessController::Levels::Medium) {
+ lv_obj_set_state(indicators[1], LV_STATE_DEFAULT);
+ lv_obj_set_state(indicators[2], LV_STATE_DISABLED);
+ } else {
+ lv_obj_set_state(indicators[1], LV_STATE_DISABLED);
+ lv_obj_set_state(indicators[2], LV_STATE_DISABLED);
+ }
+}
+
+void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
+ if (obj == backgroundAction && event == LV_EVENT_CLICKED) {
+ isOn = !isOn;
+ SetColors();
}
}
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
+ using namespace Pinetime::Controllers;
+
+ if (event == TouchEvents::SwipeLeft) {
+ if (brightnessLevel == BrightnessController::Levels::High) {
+ brightnessLevel = BrightnessController::Levels::Medium;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ } else if (brightnessLevel == BrightnessController::Levels::Medium) {
+ brightnessLevel = BrightnessController::Levels::Low;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ }
+ return true;
+ }
+ if (event == TouchEvents::SwipeRight) {
+ if (brightnessLevel == BrightnessController::Levels::Low) {
+ brightnessLevel = BrightnessController::Levels::Medium;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ } else if (brightnessLevel == BrightnessController::Levels::Medium) {
+ brightnessLevel = BrightnessController::Levels::High;
+ brightnessController.Set(brightnessLevel);
+ SetIndicators();
+ }
+ return true;
+ }
+
return false;
}
diff --git a/src/displayapp/screens/FlashLight.h b/src/displayapp/screens/FlashLight.h
index 7f5ca6c5..f2c65bbe 100644
--- a/src/displayapp/screens/FlashLight.h
+++ b/src/displayapp/screens/FlashLight.h
@@ -1,10 +1,10 @@
#pragma once
-#include <cstdint>
#include "Screen.h"
-#include <lvgl/lvgl.h>
-#include "systemtask/SystemTask.h"
#include "components/brightness/BrightnessController.h"
+#include "systemtask/SystemTask.h"
+#include <cstdint>
+#include <lvgl/lvgl.h>
namespace Pinetime {
@@ -20,12 +20,18 @@ namespace Pinetime {
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
private:
+ void SetIndicators();
+ void SetColors();
+
Pinetime::System::SystemTask& systemTask;
- Controllers::BrightnessController& brightness;
+ Controllers::BrightnessController& brightnessController;
+
+ Controllers::BrightnessController::Levels brightnessLevel;
lv_obj_t* flashLight;
lv_obj_t* backgroundAction;
- bool isOn = true;
+ lv_obj_t* indicators[3];
+ bool isOn = false;
};
}
}
diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp
index 884a4a51..52cb8519 100644
--- a/src/displayapp/screens/Metronome.cpp
+++ b/src/displayapp/screens/Metronome.cpp
@@ -78,7 +78,7 @@ Metronome::~Metronome() {
void Metronome::Refresh() {
if (metronomeStarted) {
- if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) {
+ if (xTaskGetTickCount() - startTime > 60u * configTICK_RATE_HZ / static_cast<uint16_t>(bpm)) {
startTime += 60 * configTICK_RATE_HZ / bpm;
counter--;
if (counter == 0) {
diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp
index 417dff00..4f475813 100644
--- a/src/displayapp/screens/Notifications.cpp
+++ b/src/displayapp/screens/Notifications.cpp
@@ -129,10 +129,6 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
alertNotificationService);
}
return true;
- case Pinetime::Applications::TouchEvents::LongTap: {
- // notificationManager.ToggleVibrations();
- return true;
- }
default:
return false;
}
diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp
index 3b6d60e3..26c2368b 100644
--- a/src/displayapp/screens/Paddle.cpp
+++ b/src/displayapp/screens/Paddle.cpp
@@ -47,8 +47,8 @@ void Paddle::Refresh() {
dy *= -1;
}
- // checks if it has touched the side (left side)
- if (ballX >= LV_VER_RES - ballSize - 1) {
+ // checks if it has touched the side (right side)
+ if (ballX >= LV_HOR_RES - ballSize - 1) {
dx *= -1;
}
diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp
index 7a712f43..fa88d459 100644
--- a/src/displayapp/screens/PineTimeStyle.cpp
+++ b/src/displayapp/screens/PineTimeStyle.cpp
@@ -1,5 +1,5 @@
/*
- * This file is part of the Infinitime distribution (https://github.com/JF002/Infinitime).
+ * This file is part of the Infinitime distribution (https://github.com/InfiniTimeOrg/Infinitime).
* Copyright (c) 2021 Kieran Cawthray.
*
* This program is free software: you can redistribute it and/or modify
@@ -100,10 +100,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_label_set_text(batteryIcon, Symbols::batteryFull);
lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
-
- batteryPlug = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_align(batteryPlug, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
+ lv_obj_set_auto_realign(batteryIcon, true);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
@@ -205,18 +202,24 @@ PineTimeStyle::~PineTimeStyle() {
lv_obj_clean(lv_scr_act());
}
+void PineTimeStyle::SetBatteryIcon() {
+ auto batteryPercent = batteryPercentRemaining.Get();
+ lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+}
+
void PineTimeStyle::Refresh() {
- batteryPercentRemaining = batteryController.PercentRemaining();
- if (batteryPercentRemaining.IsUpdated()) {
- auto batteryPercent = batteryPercentRemaining.Get();
- if (batteryController.IsCharging()) {
- auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
- lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
- lv_obj_realign(batteryPlug);
- lv_label_set_text(batteryIcon, "");
+ isCharging = batteryController.IsCharging();
+ if (isCharging.IsUpdated()) {
+ if (isCharging.Get()) {
+ lv_label_set_text(batteryIcon, Symbols::plug);
} else {
- lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
- lv_label_set_text(batteryPlug, "");
+ SetBatteryIcon();
+ }
+ }
+ if (!isCharging.Get()) {
+ batteryPercentRemaining = batteryController.PercentRemaining();
+ if (batteryPercentRemaining.IsUpdated()) {
+ SetBatteryIcon();
}
}
diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h
index cb74ead5..ba473806 100644
--- a/src/displayapp/screens/PineTimeStyle.h
+++ b/src/displayapp/screens/PineTimeStyle.h
@@ -41,6 +41,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
+ DirtyValue<bool> isCharging {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};
@@ -58,7 +59,6 @@ namespace Pinetime {
lv_obj_t* backgroundLabel;
lv_obj_t* batteryIcon;
lv_obj_t* bleIcon;
- lv_obj_t* batteryPlug;
lv_obj_t* calendarOuter;
lv_obj_t* calendarInner;
lv_obj_t* calendarBar1;
@@ -76,6 +76,8 @@ namespace Pinetime {
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
+ void SetBatteryIcon();
+
lv_task_t* taskRefresh;
};
}
diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index b7a4fc60..343b72bf 100644
--- a/src/displayapp/screens/SystemInfo.cpp
+++ b/src/displayapp/screens/SystemInfo.cpp
@@ -33,7 +33,8 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::WatchdogView& watchdog,
- Pinetime::Controllers::MotionController& motionController)
+ Pinetime::Controllers::MotionController& motionController,
+ Pinetime::Drivers::Cst816S& touchPanel)
: Screen(app),
dateTimeController {dateTimeController},
batteryController {batteryController},
@@ -41,6 +42,7 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
bleController {bleController},
watchdog {watchdog},
motionController{motionController},
+ touchPanel{touchPanel},
screens {app,
0,
{[this]() -> std::unique_ptr<Screen> {
@@ -141,7 +143,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
"#444444 Battery# %d%%/%03imV\n"
"#444444 Backlight# %s\n"
"#444444 Last reset# %s\n"
- "#444444 Accel.# %s\n",
+ "#444444 Accel.# %s\n"
+ "#444444 Touch.# %x.%x.%x\n",
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Year(),
@@ -156,7 +159,10 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
batteryController.Voltage(),
brightnessController.ToString(),
resetReason,
- ToString(motionController.DeviceType()));
+ ToString(motionController.DeviceType()),
+ touchPanel.GetChipId(),
+ touchPanel.GetVendorId(),
+ touchPanel.GetFwVersion());
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::make_unique<Screens::Label>(1, 5, app, label);
}
@@ -200,11 +206,14 @@ bool SystemInfo::sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
}
std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
- TaskStatus_t tasksStatus[10];
+ static constexpr uint8_t maxTaskCount = 9;
+ TaskStatus_t tasksStatus[maxTaskCount];
+
lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
lv_table_set_col_cnt(infoTask, 4);
- lv_table_set_row_cnt(infoTask, 8);
- lv_obj_set_pos(infoTask, 0, 10);
+ lv_table_set_row_cnt(infoTask, maxTaskCount + 1);
+ lv_obj_set_style_local_pad_all(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 0);
+ lv_obj_set_style_local_border_color(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_table_set_cell_value(infoTask, 0, 0, "#");
lv_table_set_col_width(infoTask, 0, 30);
@@ -215,9 +224,9 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
lv_table_set_cell_value(infoTask, 0, 3, "Free");
lv_table_set_col_width(infoTask, 3, 90);
- auto nb = uxTaskGetSystemState(tasksStatus, sizeof(tasksStatus) / sizeof(tasksStatus[0]), nullptr);
+ auto nb = uxTaskGetSystemState(tasksStatus, maxTaskCount, nullptr);
std::sort(tasksStatus, tasksStatus + nb, sortById);
- for (uint8_t i = 0; i < nb && i < 7; i++) {
+ for (uint8_t i = 0; i < nb && i < maxTaskCount; i++) {
lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
char state[2] = {0};
@@ -261,7 +270,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen5() {
"Public License v3\n"
"#444444 Source code#\n"
"#FFFF00 https://github.com/#\n"
- "#FFFF00 JF002/InfiniTime#");
+ "#FFFF00 InfiniTimeOrg/#\n"
+ "#FFFF00 InfiniTime#");
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::make_unique<Screens::Label>(4, 5, app, label);
diff --git a/src/displayapp/screens/SystemInfo.h b/src/displayapp/screens/SystemInfo.h
index 5eb7054d..bfcc3aa4 100644
--- a/src/displayapp/screens/SystemInfo.h
+++ b/src/displayapp/screens/SystemInfo.h
@@ -28,7 +28,8 @@ namespace Pinetime {
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::Ble& bleController,
Pinetime::Drivers::WatchdogView& watchdog,
- Pinetime::Controllers::MotionController& motionController);
+ Pinetime::Controllers::MotionController& motionController,
+ Pinetime::Drivers::Cst816S& touchPanel);
~SystemInfo() override;
bool OnTouchEvent(TouchEvents event) override;
@@ -39,6 +40,7 @@ namespace Pinetime {
Pinetime::Controllers::Ble& bleController;
Pinetime::Drivers::WatchdogView& watchdog;
Pinetime::Controllers::MotionController& motionController;
+ Pinetime::Drivers::Cst816S& touchPanel;
ScreenList<5> screens;
diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp
index 75e35c1b..53e7faf7 100644
--- a/src/displayapp/screens/WatchFaceAnalog.cpp
+++ b/src/displayapp/screens/WatchFaceAnalog.cpp
@@ -68,6 +68,7 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text(batteryIcon, Symbols::batteryHalf);
lv_obj_align(batteryIcon, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
+ lv_obj_set_auto_realign(batteryIcon, true);
notificationIcon = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
@@ -176,11 +177,31 @@ void WatchFaceAnalog::UpdateClock() {
}
}
+void WatchFaceAnalog::SetBatteryIcon() {
+ auto batteryPercent = batteryPercentRemaining.Get();
+ if (batteryPercent == 100) {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ } else {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ }
+ lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+}
+
void WatchFaceAnalog::Refresh() {
- batteryPercentRemaining = batteryController.PercentRemaining();
- if (batteryPercentRemaining.IsUpdated()) {
- auto batteryPercent = batteryPercentRemaining.Get();
- lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+ isCharging = batteryController.IsCharging();
+ if (isCharging.IsUpdated()) {
+ if (isCharging.Get()) {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
+ lv_label_set_text(batteryIcon, Symbols::plug);
+ } else {
+ SetBatteryIcon();
+ }
+ }
+ if (!isCharging.Get()) {
+ batteryPercentRemaining = batteryController.PercentRemaining();
+ if (batteryPercentRemaining.IsUpdated()) {
+ SetBatteryIcon();
+ }
}
notificationState = notificationManager.AreNewNotificationsAvailable();
diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h
index 406f4d50..001414a6 100644
--- a/src/displayapp/screens/WatchFaceAnalog.h
+++ b/src/displayapp/screens/WatchFaceAnalog.h
@@ -49,6 +49,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {0};
+ DirtyValue<bool> isCharging {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
DirtyValue<bool> notificationState {false};
@@ -81,6 +82,7 @@ namespace Pinetime {
Controllers::Settings& settingsController;
void UpdateClock();
+ void SetBatteryIcon();
lv_task_t* taskRefresh;
};
diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp
index 58ab6190..2ecab609 100644
--- a/src/displayapp/screens/WatchFaceDigital.cpp
+++ b/src/displayapp/screens/WatchFaceDigital.cpp
@@ -102,12 +102,20 @@ WatchFaceDigital::~WatchFaceDigital() {
}
void WatchFaceDigital::Refresh() {
+ powerPresent = batteryController.IsPowerPresent();
+ if (powerPresent.IsUpdated()) {
+ lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
+ }
+
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
+ if (batteryPercent == 100) {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ } else {
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ }
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
- auto isCharging = batteryController.IsCharging() or batteryController.IsPowerPresent();
- lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
}
bleState = bleController.IsConnected();
diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h
index 48dc1373..e27545f3 100644
--- a/src/displayapp/screens/WatchFaceDigital.h
+++ b/src/displayapp/screens/WatchFaceDigital.h
@@ -44,6 +44,7 @@ namespace Pinetime {
uint8_t currentDay = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
+ DirtyValue<bool> powerPresent {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
DirtyValue<bool> motionSensorOk {};
diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp
index 22b56360..dd626072 100644
--- a/src/displayapp/screens/settings/QuickSettings.cpp
+++ b/src/displayapp/screens/settings/QuickSettings.cpp
@@ -88,7 +88,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
btn3_lvl = lv_label_create(btn3, nullptr);
lv_obj_set_style_local_text_font(btn3_lvl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
- if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::ON) {
+ if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::ON) {
lv_obj_add_state(btn3, LV_STATE_CHECKED);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
@@ -131,7 +131,7 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if (object == btn2 && event == LV_EVENT_CLICKED) {
running = false;
- app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::None);
+ app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::Up);
} else if (object == btn1 && event == LV_EVENT_CLICKED) {
@@ -142,11 +142,11 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
} else if (object == btn3 && event == LV_EVENT_VALUE_CHANGED) {
if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) {
- settingsController.SetVibrationStatus(Controllers::Settings::Vibration::ON);
+ settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON);
motorController.RunForDuration(35);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
- settingsController.SetVibrationStatus(Controllers::Settings::Vibration::OFF);
+ settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
}
diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp
new file mode 100644
index 00000000..ba3413ef
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetDate.cpp
@@ -0,0 +1,198 @@
+#include "SettingSetDate.h"
+#include <lvgl/lvgl.h>
+#include <hal/nrf_rtc.h>
+#include <nrf_log.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ constexpr int16_t POS_X_DAY = -72;
+ constexpr int16_t POS_X_MONTH = 0;
+ constexpr int16_t POS_X_YEAR = 72;
+ constexpr int16_t POS_Y_PLUS = -50;
+ constexpr int16_t POS_Y_TEXT = -6;
+ constexpr int16_t POS_Y_MINUS = 40;
+
+ void event_handler(lv_obj_t * obj, lv_event_t event) {
+ auto* screen = static_cast<SettingSetDate *>(obj->user_data);
+ screen->HandleButtonPress(obj, event);
+ }
+}
+
+SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) :
+ Screen(app),
+ dateTimeController {dateTimeController} {
+ lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_static(title, "Set current date");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15);
+
+ lv_obj_t * icon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+
+ lv_label_set_text_static(icon, Symbols::clock);
+ lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
+
+ dayValue = static_cast<int>(dateTimeController.Day());
+ lblDay = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_label_set_align(lblDay, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblDay, true);
+
+ monthValue = static_cast<int>(dateTimeController.Month());
+ lblMonth = lv_label_create(lv_scr_act(), nullptr);
+ UpdateMonthLabel();
+ lv_label_set_align(lblMonth, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblMonth, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblMonth, true);
+
+ yearValue = static_cast<int>(dateTimeController.Year());
+ if (yearValue < 2021)
+ yearValue = 2021;
+ lblYear = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_fmt(lblYear, "%d", yearValue);
+ lv_label_set_align(lblYear, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblYear, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblYear, true);
+
+ btnDayPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnDayPlus->user_data = this;
+ lv_obj_set_size(btnDayPlus, 50, 40);
+ lv_obj_align(btnDayPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_PLUS);
+ lv_obj_set_style_local_value_str(btnDayPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnDayPlus, event_handler);
+
+ btnDayMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnDayMinus->user_data = this;
+ lv_obj_set_size(btnDayMinus, 50, 40);
+ lv_obj_align(btnDayMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_MINUS);
+ lv_obj_set_style_local_value_str(btnDayMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnDayMinus, event_handler);
+
+ btnMonthPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMonthPlus->user_data = this;
+ lv_obj_set_size(btnMonthPlus, 50, 40);
+ lv_obj_align(btnMonthPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_PLUS);
+ lv_obj_set_style_local_value_str(btnMonthPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnMonthPlus, event_handler);
+
+ btnMonthMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMonthMinus->user_data = this;
+ lv_obj_set_size(btnMonthMinus, 50, 40);
+ lv_obj_align(btnMonthMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_MINUS);
+ lv_obj_set_style_local_value_str(btnMonthMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnMonthMinus, event_handler);
+
+ btnYearPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnYearPlus->user_data = this;
+ lv_obj_set_size(btnYearPlus, 50, 40);
+ lv_obj_align(btnYearPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_PLUS);
+ lv_obj_set_style_local_value_str(btnYearPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnYearPlus, event_handler);
+
+ btnYearMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnYearMinus->user_data = this;
+ lv_obj_set_size(btnYearMinus, 50, 40);
+ lv_obj_align(btnYearMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_MINUS);
+ lv_obj_set_style_local_value_str(btnYearMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnYearMinus, event_handler);
+
+ btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnSetTime->user_data = this;
+ lv_obj_set_size(btnSetTime, 120, 48);
+ lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
+ lv_obj_set_event_cb(btnSetTime, event_handler);
+}
+
+SettingSetDate::~SettingSetDate() {
+ lv_obj_clean(lv_scr_act());
+}
+
+void SettingSetDate::HandleButtonPress(lv_obj_t *object, lv_event_t event) {
+ if (event != LV_EVENT_CLICKED)
+ return;
+
+ if (object == btnDayPlus) {
+ dayValue++;
+ if (dayValue > MaximumDayOfMonth())
+ dayValue = 1;
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnDayMinus) {
+ dayValue--;
+ if (dayValue < 1)
+ dayValue = MaximumDayOfMonth();
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnMonthPlus) {
+ monthValue++;
+ if (monthValue > 12)
+ monthValue = 1;
+ UpdateMonthLabel();
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnMonthMinus) {
+ monthValue--;
+ if (monthValue < 1)
+ monthValue = 12;
+ UpdateMonthLabel();
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnYearPlus) {
+ yearValue++;
+ lv_label_set_text_fmt(lblYear, "%d", yearValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnYearMinus) {
+ yearValue--;
+ lv_label_set_text_fmt(lblYear, "%d", yearValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ CheckDay();
+ } else if (object == btnSetTime) {
+ NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue);
+ dateTimeController.SetTime(static_cast<uint16_t>(yearValue),
+ static_cast<uint8_t>(monthValue),
+ static_cast<uint8_t>(dayValue),
+ 0,
+ dateTimeController.Hours(),
+ dateTimeController.Minutes(),
+ dateTimeController.Seconds(),
+ nrf_rtc_counter_get(portNRF_RTC_REG));
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
+ }
+}
+
+int SettingSetDate::MaximumDayOfMonth() const {
+ switch (monthValue) {
+ case 2:
+ if ((((yearValue % 4) == 0) && ((yearValue % 100) != 0)) || ((yearValue % 400) == 0))
+ return 29;
+ return 28;
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ return 30;
+ default:
+ return 31;
+ }
+}
+
+void SettingSetDate::CheckDay() {
+ int maxDay = MaximumDayOfMonth();
+ if (dayValue > maxDay) {
+ dayValue = maxDay;
+ lv_label_set_text_fmt(lblDay, "%d", dayValue);
+ lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
+ }
+}
+
+void SettingSetDate::UpdateMonthLabel() {
+ lv_label_set_text_static(
+ lblMonth, Pinetime::Controllers::DateTime::MonthShortToStringLow(static_cast<Pinetime::Controllers::DateTime::Months>(monthValue)));
+}
diff --git a/src/displayapp/screens/settings/SettingSetDate.h b/src/displayapp/screens/settings/SettingSetDate.h
new file mode 100644
index 00000000..477337ff
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetDate.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/datetime/DateTimeController.h"
+#include "displayapp/screens/Screen.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class SettingSetDate : public Screen{
+ public:
+ SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController);
+ ~SettingSetDate() override;
+
+ void HandleButtonPress(lv_obj_t *object, lv_event_t event);
+
+ private:
+ Controllers::DateTime& dateTimeController;
+
+ int dayValue;
+ int monthValue;
+ int yearValue;
+ lv_obj_t * lblDay;
+ lv_obj_t * lblMonth;
+ lv_obj_t * lblYear;
+ lv_obj_t * btnDayPlus;
+ lv_obj_t * btnDayMinus;
+ lv_obj_t * btnMonthPlus;
+ lv_obj_t * btnMonthMinus;
+ lv_obj_t * btnYearPlus;
+ lv_obj_t * btnYearMinus;
+ lv_obj_t * btnSetTime;
+
+ int MaximumDayOfMonth() const;
+ void CheckDay();
+ void UpdateMonthLabel();
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp
new file mode 100644
index 00000000..194bf5eb
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetTime.cpp
@@ -0,0 +1,154 @@
+#include "SettingSetTime.h"
+#include <lvgl/lvgl.h>
+#include <hal/nrf_rtc.h>
+#include <nrf_log.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ constexpr int16_t POS_X_HOURS = -72;
+ constexpr int16_t POS_X_MINUTES = 0;
+ constexpr int16_t POS_X_SECONDS = 72;
+ constexpr int16_t POS_Y_PLUS = -50;
+ constexpr int16_t POS_Y_TEXT = -6;
+ constexpr int16_t POS_Y_MINUS = 40;
+ constexpr int16_t OFS_Y_COLON = -2;
+
+ void event_handler(lv_obj_t * obj, lv_event_t event) {
+ auto* screen = static_cast<SettingSetTime *>(obj->user_data);
+ screen->HandleButtonPress(obj, event);
+ }
+}
+
+SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) :
+ Screen(app),
+ dateTimeController {dateTimeController} {
+ lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_static(title, "Set current time");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15);
+
+ lv_obj_t * icon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
+
+ lv_label_set_text_static(icon, Symbols::clock);
+ lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
+
+ hoursValue = static_cast<int>(dateTimeController.Hours());
+ lblHours = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblHours, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
+ lv_label_set_align(lblHours, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblHours, lv_scr_act(), LV_ALIGN_CENTER, POS_X_HOURS, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblHours, true);
+
+ lv_obj_t * lblColon1 = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblColon1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_static(lblColon1, ":");
+ lv_label_set_align(lblColon1, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblColon1, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_HOURS + POS_X_MINUTES) / 2, POS_Y_TEXT + OFS_Y_COLON);
+
+ minutesValue = static_cast<int>(dateTimeController.Minutes());
+ lblMinutes = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
+ lv_label_set_align(lblMinutes, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblMinutes, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MINUTES, POS_Y_TEXT);
+ lv_obj_set_auto_realign(lblMinutes, true);
+
+ lv_obj_t * lblColon2 = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblColon2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_static(lblColon2, ":");
+ lv_label_set_align(lblColon2, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblColon2, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_MINUTES + POS_X_SECONDS) / 2, POS_Y_TEXT + OFS_Y_COLON);
+
+ lv_obj_t * lblSeconds = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(lblSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text_static(lblSeconds, "00");
+ lv_label_set_align(lblSeconds, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(lblSeconds, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT);
+
+ btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursPlus->user_data = this;
+ lv_obj_set_size(btnHoursPlus, 50, 40);
+ lv_obj_align(btnHoursPlus, lv_scr_act(), LV_ALIGN_CENTER, -72, -50);
+ lv_obj_set_style_local_value_str(btnHoursPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnHoursPlus, event_handler);
+
+ btnHoursMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnHoursMinus->user_data = this;
+ lv_obj_set_size(btnHoursMinus, 50, 40);
+ lv_obj_align(btnHoursMinus, lv_scr_act(), LV_ALIGN_CENTER, -72, 40);
+ lv_obj_set_style_local_value_str(btnHoursMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnHoursMinus, event_handler);
+
+ btnMinutesPlus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesPlus->user_data = this;
+ lv_obj_set_size(btnMinutesPlus, 50, 40);
+ lv_obj_align(btnMinutesPlus, lv_scr_act(), LV_ALIGN_CENTER, 0, -50);
+ lv_obj_set_style_local_value_str(btnMinutesPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
+ lv_obj_set_event_cb(btnMinutesPlus, event_handler);
+
+ btnMinutesMinus = lv_btn_create(lv_scr_act(), nullptr);
+ btnMinutesMinus->user_data = this;
+ lv_obj_set_size(btnMinutesMinus, 50, 40);
+ lv_obj_align(btnMinutesMinus, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
+ lv_obj_set_style_local_value_str(btnMinutesMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
+ lv_obj_set_event_cb(btnMinutesMinus, event_handler);
+
+ btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnSetTime->user_data = this;
+ lv_obj_set_size(btnSetTime, 120, 48);
+ lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
+ lv_obj_set_event_cb(btnSetTime, event_handler);
+}
+
+SettingSetTime::~SettingSetTime() {
+ lv_obj_clean(lv_scr_act());
+}
+
+void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) {
+ if (event != LV_EVENT_CLICKED)
+ return;
+
+ if (object == btnHoursPlus) {
+ hoursValue++;
+ if (hoursValue > 23)
+ hoursValue = 0;
+ lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnHoursMinus) {
+ hoursValue--;
+ if (hoursValue < 0)
+ hoursValue = 23;
+ lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnMinutesPlus) {
+ minutesValue++;
+ if (minutesValue > 59)
+ minutesValue = 0;
+ lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnMinutesMinus) {
+ minutesValue--;
+ if (minutesValue < 0)
+ minutesValue = 59;
+ lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
+ } else if (object == btnSetTime) {
+ NRF_LOG_INFO("Setting time (manually) to %02d:%02d:00", hoursValue, minutesValue);
+ dateTimeController.SetTime(dateTimeController.Year(),
+ static_cast<uint8_t>(dateTimeController.Month()),
+ dateTimeController.Day(),
+ static_cast<uint8_t>(dateTimeController.DayOfWeek()),
+ static_cast<uint8_t>(hoursValue),
+ static_cast<uint8_t>(minutesValue),
+ 0,
+ nrf_rtc_counter_get(portNRF_RTC_REG));
+ lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h
new file mode 100644
index 00000000..8ba41eae
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingSetTime.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/datetime/DateTimeController.h"
+#include "displayapp/screens/Screen.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class SettingSetTime : public Screen{
+ public:
+ SettingSetTime(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController);
+ ~SettingSetTime() override;
+
+ void HandleButtonPress(lv_obj_t *object, lv_event_t event);
+
+ private:
+ Controllers::DateTime& dateTimeController;
+
+ int hoursValue;
+ int minutesValue;
+ lv_obj_t * lblHours;
+ lv_obj_t * lblMinutes;
+ lv_obj_t * btnHoursPlus;
+ lv_obj_t * btnHoursMinus;
+ lv_obj_t * btnMinutesPlus;
+ lv_obj_t * btnMinutesMinus;
+ lv_obj_t * btnSetTime;
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp
index e3319f03..1daf311e 100644
--- a/src/displayapp/screens/settings/Settings.cpp
+++ b/src/displayapp/screens/settings/Settings.cpp
@@ -49,9 +49,9 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::shoe, "Steps", Apps::SettingSteps},
- {Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
- {Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle},
- {Symbols::check, "Firmware", Apps::FirmwareValidation},
+ {Symbols::clock, "Set date", Apps::SettingSetDate},
+ {Symbols::clock, "Set time", Apps::SettingSetTime},
+ {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}
}};
return std::make_unique<Screens::List>(1, 3, app, settingsController, applications);
@@ -60,10 +60,10 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
std::unique_ptr<Screen> Settings::CreateScreen3() {
std::array<Screens::List::Applications, 4> applications {{
+ {Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle},
+ {Symbols::check, "Firmware", Apps::FirmwareValidation},
{Symbols::list, "About", Apps::SysInfo},
{Symbols::none, "None", Apps::None},
- {Symbols::none, "None", Apps::None},
- {Symbols::none, "None", Apps::None},
}};
return std::make_unique<Screens::List>(2, 3, app, settingsController, applications);
diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp
index 61d540c1..7fc8eca4 100644
--- a/src/drivers/Cst816s.cpp
+++ b/src/drivers/Cst816s.cpp
@@ -18,7 +18,7 @@ using namespace Pinetime::Drivers;
Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} {
}
-void Cst816S::Init() {
+bool Cst816S::Init() {
nrf_gpio_cfg_output(PinMap::Cst816sReset);
nrf_gpio_pin_clear(PinMap::Cst816sReset);
vTaskDelay(5);
@@ -49,10 +49,27 @@ void Cst816S::Init() {
*/
static constexpr uint8_t irqCtl = 0b01110000;
twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1);
+
+ // There's mixed information about which register contains which information
+ if (twiMaster.Read(twiAddress, 0xA7, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) {
+ chipId = 0xFF;
+ return false;
+ }
+ if (twiMaster.Read(twiAddress, 0xA8, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) {
+ vendorId = 0xFF;
+ return false;
+ }
+ if (twiMaster.Read(twiAddress, 0xA9, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) {
+ fwVersion = 0xFF;
+ return false;
+ }
+
+ return chipId == 0xb4 && vendorId == 0 && fwVersion == 1;
}
Cst816S::TouchInfos Cst816S::GetTouchInfo() {
Cst816S::TouchInfos info;
+ uint8_t touchData[7];
auto ret = twiMaster.Read(twiAddress, 0, touchData, sizeof(touchData));
if (ret != TwiMaster::ErrorCodes::NoError) {
@@ -60,18 +77,17 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
return info;
}
- auto nbTouchPoints = touchData[2] & 0x0f;
+ // This can only be 0 or 1
+ uint8_t nbTouchPoints = touchData[touchPointNumIndex] & 0x0f;
- auto xHigh = touchData[touchXHighIndex] & 0x0f;
- auto xLow = touchData[touchXLowIndex];
- uint16_t x = (xHigh << 8) | xLow;
+ uint8_t xHigh = touchData[touchXHighIndex] & 0x0f;
+ uint8_t xLow = touchData[touchXLowIndex];
+ info.x = (xHigh << 8) | xLow;
- auto yHigh = touchData[touchYHighIndex] & 0x0f;
- auto yLow = touchData[touchYLowIndex];
- uint16_t y = (yHigh << 8) | yLow;
+ uint8_t yHigh = touchData[touchYHighIndex] & 0x0f;
+ uint8_t yLow = touchData[touchYLowIndex];
+ info.y = (yHigh << 8) | yLow;
- info.x = x;
- info.y = y;
info.touching = (nbTouchPoints > 0);
info.gesture = static_cast<Gestures>(touchData[gestureIndex]);
diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h
index 7b46c5d5..0fec8419 100644
--- a/src/drivers/Cst816s.h
+++ b/src/drivers/Cst816s.h
@@ -30,11 +30,20 @@ namespace Pinetime {
Cst816S(Cst816S&&) = delete;
Cst816S& operator=(Cst816S&&) = delete;
- void Init();
+ bool Init();
TouchInfos GetTouchInfo();
void Sleep();
void Wakeup();
+ uint8_t GetChipId() const {
+ return chipId;
+ }
+ uint8_t GetVendorId() const {
+ return vendorId;
+ }
+ uint8_t GetFwVersion() const {
+ return fwVersion;
+ }
private:
// Unused/Unavailable commented out
static constexpr uint8_t gestureIndex = 1;
@@ -49,9 +58,12 @@ namespace Pinetime {
//static constexpr uint8_t touchXYIndex = 7;
//static constexpr uint8_t touchMiscIndex = 8;
- uint8_t touchData[7];
TwiMaster& twiMaster;
uint8_t twiAddress;
+
+ uint8_t chipId;
+ uint8_t vendorId;
+ uint8_t fwVersion;
};
}
diff --git a/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h b/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h
index 37b81a88..5e2d636f 100644
--- a/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h
+++ b/src/libs/mynewt-nimble/nimble/controller/include/controller/ble_ll_rfmgmt.h
@@ -51,7 +51,7 @@ static inline void ble_ll_rfmgmt_reset(void) { }
static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { }
static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { }
static inline void ble_ll_rfmgmt_release(void) { }
-static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; }
+static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return os_cputime_get32(); }
static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; }
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 0d4ba42f..fc772355 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -108,12 +108,12 @@ Pinetime::Drivers::WatchdogView watchdogView(watchdog);
Pinetime::Controllers::NotificationManager notificationManager;
Pinetime::Controllers::MotionController motionController;
Pinetime::Controllers::TimerController timerController;
+Pinetime::Controllers::AlarmController alarmController {dateTimeController};
Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
Pinetime::Controllers::FS fs {spiNorFlash};
Pinetime::Controllers::Settings settingsController {fs};
-Pinetime::Controllers::MotorController motorController {settingsController};
-
+Pinetime::Controllers::MotorController motorController {};
Pinetime::Applications::DisplayApp displayApp(lcd,
lvgl,
@@ -128,6 +128,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd,
motorController,
motionController,
timerController,
+ alarmController,
touchHandler);
Pinetime::System::SystemTask systemTask(spi,
@@ -140,6 +141,7 @@ Pinetime::System::SystemTask systemTask(spi,
bleController,
dateTimeController,
timerController,
+ alarmController,
watchdog,
notificationManager,
motorController,
@@ -153,6 +155,16 @@ Pinetime::System::SystemTask systemTask(spi,
fs,
touchHandler);
+/* Variable Declarations for variables in noinit SRAM
+ Increment NoInit_MagicValue upon adding variables to this area
+*/
+extern uint32_t __start_noinit_data;
+extern uint32_t __stop_noinit_data;
+static constexpr uint32_t NoInit_MagicValue = 0xDEAD0000;
+uint32_t NoInit_MagicWord __attribute__((section(".noinit")));
+std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime __attribute__((section(".noinit")));
+
+
void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
if (pin == Pinetime::PinMap::Cst816sIrq) {
systemTask.OnTouchEvent();
@@ -313,6 +325,15 @@ int main(void) {
// retrieve version stored by bootloader
Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]);
+
+ if (NoInit_MagicWord == NoInit_MagicValue) {
+ dateTimeController.SetCurrentTime(NoInit_BackUpTime);
+ } else {
+ //Clear Memory to known state
+ memset(&__start_noinit_data,0,(uintptr_t)&__stop_noinit_data-(uintptr_t)&__start_noinit_data);
+ NoInit_MagicWord = NoInit_MagicValue;
+ }
+
lvgl.Init();
systemTask.Start();
diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h
index ebe6a2b1..5aa218d2 100644
--- a/src/systemtask/Messages.h
+++ b/src/systemtask/Messages.h
@@ -21,8 +21,10 @@ namespace Pinetime {
DisableSleeping,
OnNewDay,
OnChargingEvent,
+ SetOffAlarm,
+ StopRinging,
MeasureBatteryTimerExpired,
- BatteryMeasurementDone,
+ BatteryPercentageUpdated,
};
}
}
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 0cbce6b4..f1c5165a 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -23,6 +23,7 @@
#include "drivers/Hrs3300.h"
#include "drivers/PinMap.h"
#include "main.h"
+#include "BootErrors.h"
#include <memory>
@@ -64,6 +65,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Controllers::TimerController& timerController,
+ Controllers::AlarmController& alarmController,
Drivers::Watchdog& watchdog,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::MotorController& motorController,
@@ -86,6 +88,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
bleController {bleController},
dateTimeController {dateTimeController},
timerController {timerController},
+ alarmController {alarmController},
watchdog {watchdog},
notificationManager {notificationManager},
motorController {motorController},
@@ -114,6 +117,8 @@ void SystemTask::Process(void* instance) {
}
void SystemTask::Work() {
+ BootErrors bootError = BootErrors::None;
+
watchdog.Setup(7);
watchdog.Start();
NRF_LOG_INFO("Last reset reason : %s", Pinetime::Drivers::Watchdog::ResetReasonToString(watchdog.ResetReason()));
@@ -131,14 +136,16 @@ void SystemTask::Work() {
lcd.Init();
twiMaster.Init();
- touchPanel.Init();
+ if (!touchPanel.Init()) {
+ bootError = BootErrors::TouchController;
+ }
dateTimeController.Register(this);
batteryController.Register(this);
- batteryController.Update();
motorController.Init();
motionSensor.SoftReset();
timerController.Register(this);
timerController.Init();
+ alarmController.Init(this);
// Reset the TWI device because the motion sensor chip most probably crashed it...
twiMaster.Sleep();
@@ -149,25 +156,27 @@ void SystemTask::Work() {
settingsController.Init();
displayApp.Register(this);
- displayApp.Start();
+ displayApp.Start(bootError);
heartRateSensor.Init();
heartRateSensor.Disable();
heartRateApp.Start();
- nrf_gpio_cfg_sense_input(PinMap::Button, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_High);
+ // Button
nrf_gpio_cfg_output(15);
nrf_gpio_pin_set(15);
nrfx_gpiote_in_config_t pinConfig;
- pinConfig.skip_gpio_setup = true;
+ pinConfig.skip_gpio_setup = false;
pinConfig.hi_accuracy = false;
pinConfig.is_watcher = false;
- pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO;
+ pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_TOGGLE;
pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown;
nrfx_gpiote_in_init(PinMap::Button, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_event_enable(PinMap::Button, true);
+ // Touchscreen
nrf_gpio_cfg_sense_input(PinMap::Cst816sIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low);
pinConfig.skip_gpio_setup = true;
@@ -178,18 +187,16 @@ void SystemTask::Work() {
nrfx_gpiote_in_init(PinMap::Cst816sIrq, &pinConfig, nrfx_gpiote_evt_handler);
+ // Power present
pinConfig.sense = NRF_GPIOTE_POLARITY_TOGGLE;
pinConfig.pull = NRF_GPIO_PIN_NOPULL;
pinConfig.is_watcher = false;
pinConfig.hi_accuracy = false;
- pinConfig.skip_gpio_setup = true;
+ pinConfig.skip_gpio_setup = false;
nrfx_gpiote_in_init(PinMap::PowerPresent, &pinConfig, nrfx_gpiote_evt_handler);
+ nrfx_gpiote_in_event_enable(PinMap::PowerPresent, true);
- if (nrf_gpio_pin_read(PinMap::PowerPresent)) {
- nrf_gpio_cfg_sense_input(PinMap::PowerPresent, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
- } else {
- nrf_gpio_cfg_sense_input(PinMap::PowerPresent, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
- }
+ batteryController.MeasureVoltage();
idleTimer = xTimerCreate("idleTimer", pdMS_TO_TICKS(2000), pdFALSE, this, IdleTimerCallback);
dimTimer = xTimerCreate("dimTimer", pdMS_TO_TICKS(settingsController.GetScreenTimeOut() - 2000), pdFALSE, this, DimTimerCallback);
@@ -243,12 +250,13 @@ void SystemTask::Work() {
isDimmed = false;
break;
case Messages::TouchWakeUp: {
- if(touchHandler.GetNewTouchInfo()) {
+ if (touchHandler.GetNewTouchInfo()) {
auto gesture = touchHandler.GestureGet();
- if (gesture != Pinetime::Drivers::Cst816S::Gestures::None and ((gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and
- settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or
- (gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and
- settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) {
+ if (gesture != Pinetime::Drivers::Cst816S::Gestures::None and
+ ((gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and
+ settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or
+ (gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and
+ settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) {
GoToRunning();
}
}
@@ -266,10 +274,14 @@ void SystemTask::Work() {
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime);
break;
case Messages::OnNewNotification:
- if (isSleeping && !isWakingUp) {
- GoToRunning();
+ if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) {
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ } else {
+ ReloadIdleTimer();
+ }
+ displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
}
- displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
break;
case Messages::OnTimerDone:
if (isSleeping && !isWakingUp) {
@@ -278,6 +290,16 @@ void SystemTask::Work() {
motorController.RunForDuration(35);
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TimerDone);
break;
+ case Messages::SetOffAlarm:
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ }
+ motorController.StartRinging();
+ displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered);
+ break;
+ case Messages::StopRinging:
+ motorController.StopRinging();
+ break;
case Messages::BleConnected:
ReloadIdleTimer();
isBleDiscoveryTimerRunning = true;
@@ -330,18 +352,18 @@ void SystemTask::Work() {
stepCounterMustBeReset = true;
break;
case Messages::OnChargingEvent:
- batteryController.Update();
+ batteryController.ReadPowerState();
motorController.RunForDuration(15);
+ ReloadIdleTimer();
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ }
break;
case Messages::MeasureBatteryTimerExpired:
- sendBatteryNotification = true;
- batteryController.Update();
+ batteryController.MeasureVoltage();
break;
- case Messages::BatteryMeasurementDone:
- if (sendBatteryNotification) {
- sendBatteryNotification = false;
- nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
- }
+ case Messages::BatteryPercentageUpdated:
+ nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
break;
default:
@@ -363,6 +385,7 @@ void SystemTask::Work() {
monitor.Process();
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
dateTimeController.UpdateTime(systick_counter);
+ NoInit_BackUpTime = dateTimeController.CurrentDateTime();
if (!nrf_gpio_pin_read(PinMap::Button))
watchdog.Kick();
}
diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h
index 1f8be75f..879c1be8 100644
--- a/src/systemtask/SystemTask.h
+++ b/src/systemtask/SystemTask.h
@@ -17,6 +17,7 @@
#include "components/ble/NotificationManager.h"
#include "components/motor/MotorController.h"
#include "components/timer/TimerController.h"
+#include "components/alarm/AlarmController.h"
#include "components/fs/FS.h"
#include "touchhandler/TouchHandler.h"
@@ -32,6 +33,7 @@
#include "drivers/Watchdog.h"
#include "Messages.h"
+extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime;
namespace Pinetime {
namespace Drivers {
class Cst816S;
@@ -57,6 +59,7 @@ namespace Pinetime {
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
Controllers::TimerController& timerController,
+ Controllers::AlarmController& alarmController,
Drivers::Watchdog& watchdog,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::MotorController& motorController,
@@ -101,6 +104,7 @@ namespace Pinetime {
Pinetime::Controllers::Ble& bleController;
Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Controllers::TimerController& timerController;
+ Pinetime::Controllers::AlarmController& alarmController;
QueueHandle_t systemTasksMsgQueue;
std::atomic<bool> isSleeping {false};
std::atomic<bool> isGoingToSleep {false};
@@ -129,14 +133,12 @@ namespace Pinetime {
TimerHandle_t dimTimer;
TimerHandle_t idleTimer;
TimerHandle_t measureBatteryTimer;
- bool sendBatteryNotification = false;
bool doNotGoToSleep = false;
void GoToRunning();
void UpdateMotion();
bool stepCounterMustBeReset = false;
static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000);
- TickType_t lastBatteryNotificationTime = 0;
#if configUSE_TRACE_FACILITY == 1
SystemMonitor<FreeRtosMonitor> monitor;