summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml11
-rw-r--r--.gitignore4
-rw-r--r--CMakeLists.txt4
-rw-r--r--doc/BLEFS.md167
-rw-r--r--doc/MemoryAnalysis.md22
-rw-r--r--doc/NavigationService.md4
-rw-r--r--doc/PinetimeStubWithNrf52DK.md12
-rw-r--r--doc/SPI-LCD-driver.md2
-rw-r--r--doc/SWD.md4
-rw-r--r--doc/ble.md14
-rw-r--r--doc/branches.md4
-rw-r--r--doc/buildAndProgram.md4
-rw-r--r--doc/code/Apps.md6
-rw-r--r--doc/code/Intro.md4
-rw-r--r--doc/contribute.md2
-rw-r--r--doc/gettingStarted/about-software.md10
-rw-r--r--doc/gettingStarted/gettingStarted-1.0.md2
-rw-r--r--doc/gettingStarted/ota-gadgetbridge.md2
-rw-r--r--doc/openOCD.md10
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/buttonhandler/ButtonHandler.cpp2
-rw-r--r--src/buttonhandler/ButtonHandler.h2
-rw-r--r--src/components/ble/BatteryInformationService.cpp2
-rw-r--r--src/components/ble/NimbleController.cpp6
-rw-r--r--src/components/ble/NimbleController.h2
-rw-r--r--src/components/datetime/DateTimeController.cpp19
-rw-r--r--src/components/datetime/DateTimeController.h2
-rw-r--r--src/components/motion/MotionController.cpp47
-rw-r--r--src/components/motion/MotionController.h20
-rw-r--r--src/components/settings/Settings.h36
-rw-r--r--src/displayapp/Apps.h5
-rw-r--r--src/displayapp/DisplayApp.cpp26
-rw-r--r--src/displayapp/Messages.h3
-rw-r--r--src/displayapp/screens/Clock.cpp4
-rw-r--r--src/displayapp/screens/Clock.h1
-rw-r--r--src/displayapp/screens/InfiniPaint.cpp2
-rw-r--r--src/displayapp/screens/Metronome.cpp15
-rw-r--r--src/displayapp/screens/Metronome.h2
-rw-r--r--src/displayapp/screens/Music.cpp14
-rw-r--r--src/displayapp/screens/Notifications.cpp52
-rw-r--r--src/displayapp/screens/Notifications.h10
-rw-r--r--src/displayapp/screens/PineTimeStyle.cpp403
-rw-r--r--src/displayapp/screens/PineTimeStyle.h25
-rw-r--r--src/displayapp/screens/Steps.cpp49
-rw-r--r--src/displayapp/screens/Steps.h6
-rw-r--r--src/displayapp/screens/WatchFaceDigital.cpp105
-rw-r--r--src/displayapp/screens/WatchFaceDigital.h3
-rw-r--r--src/displayapp/screens/settings/SettingChimes.cpp100
-rw-r--r--src/displayapp/screens/settings/SettingChimes.h27
-rw-r--r--src/displayapp/screens/settings/SettingPineTimeStyle.cpp318
-rw-r--r--src/displayapp/screens/settings/SettingPineTimeStyle.h56
-rw-r--r--src/displayapp/screens/settings/SettingShakeThreshold.cpp137
-rw-r--r--src/displayapp/screens/settings/SettingShakeThreshold.h36
-rw-r--r--src/displayapp/screens/settings/SettingWakeUp.cpp8
-rw-r--r--src/displayapp/screens/settings/SettingWakeUp.h2
-rw-r--r--src/displayapp/screens/settings/Settings.cpp16
-rw-r--r--src/systemtask/Messages.h2
-rw-r--r--src/systemtask/SystemTask.cpp41
-rw-r--r--src/systemtask/SystemTask.h1
59 files changed, 1255 insertions, 645 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 3b753a3..58a6393 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -113,7 +113,7 @@ jobs:
run: |
mkdir -p build
cd build
- cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=${{ runner.temp }}/arm-none-eabi -DNRF5_SDK_PATH=${{ runner.temp }}/nrf5_sdk -DUSE_OPENOCD=1 -DBUILD_DFU=1 ../
+ cmake -G Ninja -DARM_NONE_EABI_TOOLCHAIN_PATH=${{ runner.temp }}/arm-none-eabi -DNRF5_SDK_PATH=${{ runner.temp }}/nrf5_sdk -DUSE_OPENOCD=1 -DBUILD_DFU=1 ../
#########################################################################################
# Make and Upload DFU Package
@@ -125,8 +125,7 @@ jobs:
- name: Make pinetime-mcuboot-app
run: |
- cd build
- make pinetime-mcuboot-app
+ cmake --build build --target pinetime-mcuboot-app
- name: Unzip DFU package
run: |
@@ -144,8 +143,7 @@ jobs:
- name: Make pinetime-app
run: |
- cd build
- make pinetime-app
+ cmake --build build --target pinetime-app
- name: Upload standalone firmware
uses: actions/upload-artifact@v2
@@ -158,8 +156,7 @@ jobs:
- name: Make pinetime-recovery
run: |
- cd build
- make pinetime-recovery
+ cmake --build build --target pinetime-recovery
#########################################################################################
# Finish
diff --git a/.gitignore b/.gitignore
index 39fb672..0474017 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,7 @@ Testing/Temporary/
#VSCODE
.vscode/.cortex-debug.registers.state.json
.vscode/.cortex-debug.peripherals.state.json
+
+#build files
+src/nRF5_SDK_15.3.0_59ac345
+src/arm-none-eabi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b588066..8846531 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
-project(pinetime VERSION 1.7.1 LANGUAGES C CXX ASM)
+project(pinetime VERSION 1.8.0 LANGUAGES C CXX ASM)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
@@ -100,7 +100,7 @@ else()
endif()
set(VERSION_EDIT_WARNING "// Do not edit this file, it is automatically generated by CMAKE!")
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docker/post_build.sh.in ${CMAKE_CURRENT_BINARY_DIR}/post_build.sh)
diff --git a/doc/BLEFS.md b/doc/BLEFS.md
new file mode 100644
index 0000000..519d84a
--- /dev/null
+++ b/doc/BLEFS.md
@@ -0,0 +1,167 @@
+# BLE FS
+---
+
+The BLE FS protocol in InfiniTime is mostly Adafruit's BLE file transfer protocol, as described in [adafruit/Adafruit_CircuitPython_BLE_File_Transfer](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer). There are some deviations, such as the status codes. These will be described later in the document.
+
+---
+
+## UUIDs
+
+There are two relevant UUIDs in this protocol: the version characteristic, and the raw transfer characteristic.
+
+### Version
+
+UUID: `adaf0100-4669-6c65-5472-616e73666572`
+
+The version characteristic returns the version of the protocol to which the sender adheres. It returns a single unsigned 32-bit integer. The latest version at the time of writing this is 4.
+
+### Transfer
+
+UUID: `adaf0200-4669-6c65-5472-616e73666572`
+
+The transfer characteristic is responsible for all the data transfer between the client and the watch. It supports write and notify. Writing a packet on the characteristic results in a response via notify.
+
+---
+
+## Usage
+
+The separator for paths is `/`, and absolute paths must start with `/`.
+
+All of the following commands and responses are transferred via the transfer characteristic
+
+### Read file
+
+To begin reading a file, a header must first be sent. The header packet should be formatted like so:
+
+- Command (single byte): `0x10`
+- 1 byte of padding
+- Unsigned 16-bit integer encoding the length of the file path.
+- Unsigned 32-bit integer encoding the location at which to start reading the first chunk.
+- Unsigned 32-bit integer encoding the amount of bytes to be read.
+- File path: UTF-8 encoded string that is _not_ null terminated.
+
+To continue reading the file after this initial packet, the following packet should be sent until all the data has been received. No close command is required after the data has been received.
+
+- Command (single byte): `0x12`
+- Status: `0x01`
+- 2 bytes of padding
+- Unsigned 32-bit integer encoding the location at which to start reading the next chunk.
+- Unsigned 32-bit integer encoding the amount of bytes to be read. This may be different from the size in the header.
+
+Both of these commands receive the following response:
+
+- Command (single byte): `0x11`
+- Status (signed 8-bit integer)
+- 2 bytes of padding
+- Unsigned 32-bit integer encoding the offset of this chunk
+- Unsigned 32-bit integer encoding the total size of the file
+- Unsigned 32-bit integer encoding the amount of data in the current chunk
+- Contents of the current chunk
+
+### Write file
+
+To begin writing to a file, a header must first be sent. The header packet should be formatted like so:
+
+- Command (single byte): `0x20`
+- 1 byte of padding
+- Unsigned 16-bit integer encoding the length of the file path.
+- Unsigned 32-bit integer encoding the location at which to start writing to the file.
+- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution. This will be used as the modification time. At the time of writing, this is not implemented in InfiniTime, but may be in the future.
+- Unsigned 32-bit integer encoding the size of the file that will be sent
+- File path: UTF-8 encoded string that is _not_ null terminated.
+
+To continue reading the file after this initial packet, the following packet should be sent until all the data has been sent and a response had been received with 0 free space. No close command is required after the data has been received.
+
+- Command (single byte): `0x22`
+- Status: `0x01`
+- 2 bytes of padding.
+- Unsigned 32-bit integer encoding the location at which to write the next chunk.
+- Unsigned 32-bit integer encoding the amount of bytes to be written.
+- Data
+
+Both of these commands receive the following response:
+
+- Command (single byte): `0x21`
+- Status (signed 8-bit integer)
+- 2 bytes of padding
+- Unsigned 32-bit integer encoding the current offset in the file
+- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution. This will be used as the modification time. At the time of writing, this is not implemented in InfiniTime, but may be in the future.
+- Unsigned 32-bit integer encoding the amount of data the client can send until the file is full.
+
+### Delete file
+
+- Command (single byte): `0x30`
+- 1 byte of padding
+- Unsigned 16-bit integer encoding the length of the file path.
+- File path: UTF-8 encoded string that is _not_ null terminated.
+
+The response to this packet will be as follows:
+
+- Command (single byte): `0x31`
+- Status (signed 8-bit integer)
+
+### Make directory
+
+- Command (single byte): `0x40`
+- 1 byte of padding
+- Unsigned 16-bit integer encoding the length of the file path.
+- 4 bytes of padding
+- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution.
+- File path: UTF-8 encoded string that is _not_ null terminated.
+
+The response to this packet will be as follows:
+
+- Command (single byte): `0x41`
+- Status (signed 8-bit integer)
+- 6 bytes of padding
+- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution.
+
+### List directory
+
+Paths returned by this command are relative to the path given in the request
+
+- Command (single byte): `0x50`
+- 1 byte of padding
+- Unsigned 16-bit integer encoding the length of the file path.
+- File path: UTF-8 encoded string that is _not_ null terminated.
+
+The response to this packet will be as follows. Responses will be sent until the final entry, which will have entry number == total entries
+
+- Command (single byte): `0x51`
+- Status (signed 8-bit integer)
+- Unsigned 16-bit integer encoding the length of the file path.
+- Unsigned 32-bit integer encoding the entry number
+- Unsigned 32-bit integer encoding the total amount of entries
+- Flags: unsigned 32-bit integer
+ + Bit 0: Set when entry is a directory
+ + Bits 1-7: Reserved
+- Unsigned 64-bit integer encoding the unix timestamp of the modification time with nanosecond resolution
+- Unsigned 32-bit integer encoding the size of the file
+- Path: UTF-8 encoded string that is _not_ null terminated.
+
+### Move file or directory
+
+- Command (single byte): `0x60`
+- 1 byte of padding
+- Unsigned 16-bit integer encoding the length of the old path
+- Unsigned 16-bit integer encoding the length of the new path
+- Old path: UTF-8 encoded string that is _not_ null terminated.
+- 1 byte of padding
+- Newpath: UTF-8 encoded string that is _not_ null terminated.
+
+The response to this packet will be as follows:
+
+- Command (single byte): `0x61`
+- Status (signed 8-bit integer)
+
+---
+
+## Deviations
+
+This section describes the differences between Adafruit's spec and InfiniTime's implementation.
+
+### Status codes
+
+The status codes returned by InfiniTime are a signed 8-bit integer, rather than an unsigned one as described in the spec.
+
+InfiniTime uses LittleFS error codes rather than the ones described in the spec. Those codes can be found in [lfs.h](https://github.com/littlefs-project/littlefs/blob/master/lfs.h#L70). \ No newline at end of file
diff --git a/doc/MemoryAnalysis.md b/doc/MemoryAnalysis.md
index 7304e3f..376f98f 100644
--- a/doc/MemoryAnalysis.md
+++ b/doc/MemoryAnalysis.md
@@ -32,13 +32,13 @@ In this analysis, I used [Linkermapviz](https://github.com/PromyLOPh/linkermapvi
### Linkermapviz
-[Linkermapviz](https://github.com/PromyLOPh/linkermapviz) parses the MAP file and displays its content in a graphical way into an HTML page:
+[Linkermapviz](https://github.com/PromyLOPh/linkermapviz) parses the MAP file and displays its content on an HTML page as a graphic:
![linkermapviz](./memoryAnalysis/linkermapviz.png)
-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,...
+Using this tool, you can compare the relative size of symbols. This can be helpful for checking memory usage at a glance.
-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...
+Also, as Linkermapviz is written in Python, you can easily modify and adapt it to your firmware or export data in another format. For example, [here it is modified to parse the contents of the MAP file and export it in a CSV file](https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620). This file could later be opened in LibreOffice Calc where sort/filter functionality could be used to search for specific symbols in specific files...
### Puncover
[Puncover](https://github.com/HBehrens/puncover) is another useful tools that analyses the binary file generated by the compiler (the .out file that contains all debug information). It provides valuable information about the symbols (data and code): name, position, size, max stack of each functions, callers, callees...
@@ -46,8 +46,8 @@ Also, as Linkermapviz is written in Python, you can easily modify it to adapt it
Puncover is really easy to install:
- - clone the repo and cd into the cloned directory
- - setup a venv
+ - Clone the repo and cd into the cloned directory
+ - Setup a venv
- `python -m virtualenv venv`
- `source venv/bin/activate`
- Install : `pip install .`
@@ -60,13 +60,13 @@ Puncover is really easy to install:
- Launch a browser at http://localhost:5000/
### Analysis
-Using the MAP file and tools, we can easily see what symbols are using most of the FLASH memory space. In this case, with no surprise, fonts and graphics are the biggest flash space consumer.
+Using the MAP file and tools, we can easily see what symbols are using most of the flash memory. In this case, unsuprisingly, fonts and graphics are the largest use of flash memory.
![Puncover](./memoryAnalysis/puncover-all-symbols.png)
-This way, you can easily check what needs to be optimized : we should find a way to store big static data (like fonts and graphics) in the external flash memory, for example.
+This way, you can easily check what needs to be optimized. We should find a way to store big static data (like fonts and graphics) in the external flash memory, for example.
-It's always a good idea to check the flash memory space when working on the project : this way, you can easily check that your developments are using a reasonable amount of space.
+It's always a good idea to check the flash memory space when working on the project. This way, you can easily check that your developments are using a reasonable amount of space.
### Links
- Analysis with linkermapviz : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620
@@ -210,7 +210,7 @@ NRF_LOG_INFO("heap : %d", m.uordblks);
```
#### Analysis
-According to my experimentation, InfiniTime uses ~6000bytes of heap most of the time. Except when the Navigation app is launched, where the heap usage increases to... more than 9500 bytes (meaning that the heap overflows and could potentially corrupt the stack!!!). This is a bug that should be fixed in #362.
+According to my experimentation, InfiniTime uses ~6000bytes of heap most of the time. Except when the Navigation app is launched, where the heap usage exceeds 9500 bytes (meaning that the heap overflows and could potentially corrupt the stack). This is a bug that should be fixed in #362.
To know exactly what's consuming heap memory, you can `wrap` functions like `malloc()` into your own functions. In this wrapper, you can add logging code or put breakpoints:
@@ -245,7 +245,7 @@ Using this technique, I was able to trace all malloc calls at boot (boot -> digi
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-3-avoiding-heap-errors/
## LVGL
-I did a deep analysis of the usage of the buffer dedicated for lvgl (managed by lv_mem).
+I did a deep analysis of the usage of the buffer dedicated to lvgl (managed by lv_mem).
This buffer is used by lvgl to allocated memory for drivers (display/touch), screens, themes, and all widgets created by the apps.
The usage of this buffer can be monitored using this code :
@@ -256,7 +256,7 @@ lv_mem_monitor(&mon);
NRF_LOG_INFO("\t Free %d / %d -- max %d", mon.free_size, mon.total_size, mon.max_used);
```
-The most interesting metric is `mon.max_used` which specifies the maximum number of bytes that were used from this buffer since the initialization of lvgl.
+The most interesting metric is `mon.max_used` which specifies the maximum number of bytes used from this buffer since the initialization of lvgl.
According to my measurements, initializing the theme, display/touch driver and screens cost **4752** bytes!
Then, initializing the digital clock face costs **1541 bytes**.
For example a simple lv_label needs **~140 bytes** of memory.
diff --git a/doc/NavigationService.md b/doc/NavigationService.md
index fd81d0b..5a4f69e 100644
--- a/doc/NavigationService.md
+++ b/doc/NavigationService.md
@@ -1,6 +1,6 @@
# Navigation Service
## Introduction
-The navigation ble service provides 4 characteristics to allow the the watch to display navigation instructions from a companion application. The intended purpose is when performing some outdoor activities, for example running or cycling.
+The navigation ble service provides 4 characteristics to allow the watch to display navigation instructions from a companion application. This service is intended to be used when performing some outdoor activities, for example running or cycling.
The 4 characteristics are:
flag (string) - Upcoming icon name
@@ -22,7 +22,7 @@ This is a client supplied string describing the upcoming instruction such as "At
This is a short string describing the distance to the upcoming instruction such as "50 m".
## Progress (UUID 00010004-78fc-48fe-8e23-433b3a1942d0)
-The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
+The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
## Full icon list
* arrive
diff --git a/doc/PinetimeStubWithNrf52DK.md b/doc/PinetimeStubWithNrf52DK.md
index c485792..dcaad69 100644
--- a/doc/PinetimeStubWithNrf52DK.md
+++ b/doc/PinetimeStubWithNrf52DK.md
@@ -1,11 +1,11 @@
# Build a stub for PineTime using NRF52-DK
-[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official developpment kit for NRF52832 SoC from Nordic Semiconductor.
+[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official developpment kit for the NRF52832 SoC from Nordic Semiconductor used in the PineTime.
-It can be very useful for PineTime development:
- * You can use it embedded JLink SWD programmer/debugger to program and debug you code on the PineTime
- * As it's based on the same SoC than the PineTime, you can program it to actually run the same code than the PineTime.
+This development kit can be very useful for PineTime development:
+ * You can use its embedded JLink SWD programmer/debugger to program and debug your code on the PineTime
+ * As it's based on the same SoC than the PineTime, you can program it to actually run the same code as the PineTime.
-This page is about the 2nd point : we will build a stub that will allow us to run the same code than the one you could run on the PineTime. This will allow you to work more easily if you don't have a PineTime dev kit around, if you don't want to modify your dev kit for SWD programming, or if you want to use some feature from the DK (like power measurement).
+This page is about the 2nd point. We will build a stub that will allow us to run the same code you can run on the PineTime. This will allow you to work more easily if you don't have a PineTime dev kit around, if you don't want to modify your dev kit for SWD programming, or if you want to use some feature from the NRF52-DK (like power measurement).
This stub only implements the display, the button and the BLE radio. The other features from the pintime are missing:
* heart rate sensor
@@ -41,7 +41,7 @@ You just need to make the following connections:
| P0.13 | Button IN (D3 in my case) |
| GND | GND |
-You also need to enable the I/O expander to disconnect pins from buttons and led on the NRF52-DK and leave them available on the pin headers:
+You also need to enable the I/O expander to disconnect pins from the buttons and LED on the NRF52-DK and leave them available on the pin headers:
| NRF52 -DK | NRF52- DK |
| --------- | --------- |
diff --git a/doc/SPI-LCD-driver.md b/doc/SPI-LCD-driver.md
index f787aab..29f3bbf 100644
--- a/doc/SPI-LCD-driver.md
+++ b/doc/SPI-LCD-driver.md
@@ -1,6 +1,6 @@
# The SPI LCD driver
## Introduction
-The LCD controller that drive the display of the Pinetime is the Sitronix ST7789V. This controller is easy to integrate with an MCU thanks to its SPI interface, and has some interesting features like:
+The LCD controller that drives the display of the Pinetime is the [Sitronix ST7789V](https://wiki.pine64.org/images/5/54/ST7789V_v1.6.pdf). This controller is easy to integrate with an MCU thanks to its SPI interface, and has some interesting features like:
- an on-chip display data RAM that can store the whole framebuffer
- partial screen update
- hardware assisted vertical scrolling
diff --git a/doc/SWD.md b/doc/SWD.md
index 4146e6a..155983b 100644
--- a/doc/SWD.md
+++ b/doc/SWD.md
@@ -4,9 +4,9 @@ Download the files **bootloader.bin**, **image-x.y.z.bin** and **pinetime-graphi
![Image file](imageFile.png)
The bootloader reads a boot logo from the external SPI flash memory. The first step consists of flashing a tool in the MCU that will flash the boot logo into this SPI flash memory. This first step is optional but recommended (the bootloader will display garbage on screen for a few second if you don't do it).
-Using your SWD tool, flash **pinetime-graphics-x.y.z.bin** at offset **0x0000**. Reset the MCU and wait for a few second, until the logo is completely drawn on the display.
+Using your SWD tool, flash **pinetime-graphics-x.y.z.bin** at offset **0x0000**. Reset the MCU and wait for a few seconds until the logo is completely drawn on the display.
-Then, using your SWD tool, flash those file at specific offset:
+Then, using your SWD tool, flash these file at the following offsets:
- bootloader.bin : **0x0000**
- image-x.y.z.bin : **0x8000**
diff --git a/doc/ble.md b/doc/ble.md
index 2b86243..d250263 100644
--- a/doc/ble.md
+++ b/doc/ble.md
@@ -9,6 +9,7 @@ This page describes the BLE implementation and API built in this firmware.
### Table of Contents
- [BLE Connection](#ble-connection)
+- [BLE FS](#ble-fs)
- [BLE UUIDs](#ble-uuids)
- [BLE Services](#ble-services)
- [CTS](#cts)
@@ -51,6 +52,13 @@ If **CTS** is detected, it'll request the current time to the companion applicat
---
+## BLE FS
+
+The documentation for BLE FS can be found here:
+[BLEFS.md](./BLEFS.md)
+
+---
+
## BLE UUIDs
When possible, InfiniTime tries to implement BLE services defined by the BLE specification.
@@ -112,11 +120,11 @@ Reading a value from the firmware version characteristic will yield a UTF-8 enco
#### 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.
+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 notifications 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.
+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 notifications for updates as the value changes.
---
@@ -289,4 +297,4 @@ This characteristic expects a particular format:
- 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
+Write all of these together, encoded as little-endian, to the current time characteristic.
diff --git a/doc/branches.md b/doc/branches.md
index ef280f4..3c86375 100644
--- a/doc/branches.md
+++ b/doc/branches.md
@@ -1,7 +1,7 @@
# Branches
The branching model of this project is based on the workflow named [Git flow](https://nvie.com/posts/a-successful-git-branching-model/).
-It is based on 2 main branches:
+The project is based on 2 main branches:
- **master** : this branch is always ready to be deployed. It means that at any time, we should be able to build the branch and release a new version of the application.
- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable.
@@ -9,4 +9,4 @@ New features should be implemented in **feature branches** created from **develo
To release a new version of the application, when develop is considered stable, a **release** branch is created from **develop**. This can be considered as a *release candidate* branch. When everything is OK, this release branch is merged into **master** and the release is generated (a tag is applied to git, the release note is finalized, binaries are built,...) from **master**.
-Git flow also supports the creation of **hotfix** branches when a bug is discovered in a released version. The **hotfix** branch is created from **master** and will be used only to implement a fix to this bug. Multiple hotfix branches can be created for the same release if more than one bugs are discovered. \ No newline at end of file
+Git flow also supports the creation of **hotfix** branches when a bug is discovered in a released version. The **hotfix** branch is created from **master** and will be used only to implement a fix to this bug. Multiple hotfix branches can be created for the same release if multiple bugs are discovered. \ No newline at end of file
diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md
index 3686871..feef9f6 100644
--- a/doc/buildAndProgram.md
+++ b/doc/buildAndProgram.md
@@ -4,7 +4,7 @@ To build this project, you'll need:
- A cross-compiler : [ARM-GCC (9-2020-q2-update)](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update)
- The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip)
- The 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
+ - To keep the system clean, you can install python modules into a python virtual environment (`venv`)
```sh
python -m venv .venv
source .venv/bin/activate
@@ -260,4 +260,4 @@ Finally, merge them together with **mergehex**:
This file must be flashed at offset **0x00** of the internal memory of the NRF52832.
#### spinor.bin
-This file is the MCUBoot image of the last stable version of the recovery firmware. It must be flashed at offset **0x00** of the external SPINOR flash memory. \ No newline at end of file
+This file is the MCUBoot image of the last stable version of the recovery firmware. It must be flashed at offset **0x00** of the external SPINOR flash memory.
diff --git a/doc/code/Apps.md b/doc/code/Apps.md
index b1c7d20..f067b58 100644
--- a/doc/code/Apps.md
+++ b/doc/code/Apps.md
@@ -8,8 +8,8 @@ This page will teach you:
The user interface of InfiniTime is made up of **screens**.
Screens that are opened from the app launcher are considered **apps**.
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)).
+An instance of the class is created when the app is launched, and destroyed when the user exits the app.
+Apps 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.
@@ -21,7 +21,7 @@ A destructor is needed to clean up LVGL and restore any changes (for example re-
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.
+If you have any doubts, you can always look at how the other apps function for reference.
### Continuous updating
If your app needs to be updated continuously, you can do so by overriding the `Refresh()` function in your class
diff --git a/doc/code/Intro.md b/doc/code/Intro.md
index bf68c7a..23b3ade 100644
--- a/doc/code/Intro.md
+++ b/doc/code/Intro.md
@@ -24,9 +24,9 @@ There are also other tasks that are responsible for Bluetooth ("ll" and "ble" in
and periodic tasks like heartrate measurements ([heartratetask/HeartRateTask.cpp](/src/heartratetask/HeartRateTask.cpp)).
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)
+If you absolutely need to create another task, try to estimate 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.
+You can use `configMINIMAL_STACK_SIZE` which is currently set to 120 words.
## Controllers
Controllers in InfiniTime are singleton objects that can provide access to certain resources to apps.
diff --git a/doc/contribute.md b/doc/contribute.md
index b1be84a..f2a4aea 100644
--- a/doc/contribute.md
+++ b/doc/contribute.md
@@ -46,7 +46,7 @@ Other contributors can post comments about the pull request, maybe ask for more
Once the pull request is reviewed and accepted, it'll be merged into **develop** and will be released in the next version of the firmware.
-## Why all these rules?
+## Why all these rules?
Reviewing pull requests is a **very time consuming task**. Everything you do to make reviewing easier will **get your PR merged faster**.
diff --git a/doc/gettingStarted/about-software.md b/doc/gettingStarted/about-software.md
index b19a610..e935d93 100644
--- a/doc/gettingStarted/about-software.md
+++ b/doc/gettingStarted/about-software.md
@@ -12,15 +12,15 @@ InfiniTime has three distinct firmwares:
**OTA** (**O**ver **T**he **A**ir) refers to updating of the firmware over BLE (**B**luetooth **L**ow **E**nergy). This is a functionality that allows the user to update the firmware on their device wirelessly.
-**DFU** (**D**evice **F**irmware **U**pdate) is 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).
+**DFU** (**D**evice **F**irmware **U**pdate) is the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implements the (legacy) DFU protocol from Nordic Semiconductor (NRF).
## Bootloader
-Most of the time, the bootloader just runs without your intervention (update and load the firmware).
+Most of the time, the bootloader just runs without your intervention (updating and loading the firmware).
-However, you can enable 2 functionalities using the push button:
+However, you can use the bootloader to rollback to the previous firmware, or load the recovery firmware using the push button:
- - Push the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the updated one
- - Push the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
+ - Press and hold the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the current one.
+ - Press and hold the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md).
diff --git a/doc/gettingStarted/gettingStarted-1.0.md b/doc/gettingStarted/gettingStarted-1.0.md
index 30b8bdb..890164f 100644
--- a/doc/gettingStarted/gettingStarted-1.0.md
+++ b/doc/gettingStarted/gettingStarted-1.0.md
@@ -18,7 +18,7 @@ You can sync the time using companion apps.
You can also set the time in the settings without a companion app. (version >1.7.0)
-InfiniTime doesn't handle daylight savings automatically, so make sure to set the correct the time or sync it with a companion app
+InfiniTime doesn't handle daylight savings automatically, so make sure to set the correct the time or sync it with a companion app.
### Digital watch face
diff --git a/doc/gettingStarted/ota-gadgetbridge.md b/doc/gettingStarted/ota-gadgetbridge.md
index 022b5e4..fe26c03 100644
--- a/doc/gettingStarted/ota-gadgetbridge.md
+++ b/doc/gettingStarted/ota-gadgetbridge.md
@@ -18,7 +18,7 @@ Now that Gadgetbridge is connected to your PineTime, use a file browser applicat
![Gadgetbridge 3](gadgetbridge3.jpg)
-Read carefully the warning and tap **Install**:
+Read the warning carefully and tap **Install**:
![Gadgetbridge 4](gadgetbridge4.jpg)
diff --git a/doc/openOCD.md b/doc/openOCD.md
index b3661ce..df24b30 100644
--- a/doc/openOCD.md
+++ b/doc/openOCD.md
@@ -1,12 +1,12 @@
# OpenOCD and STLink
OpenOCD (**Open O**n **C**hip **D**ebugger) is an open source tool that interfaces with many SWD/JTAG debugger to provide debugging and *in-system* programming for embedded target devices.
-It supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger.
+OpenOCD supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger.
-It works on X86 computers, as well as ARM/ARM64 computers and SBC (like the RaspberryPi and Pine64 Pinebook Pro) !
+OpenOCD works on X86 computers, ARM/ARM64 computers, and SBCs (like the RaspberryPi and Pine64 Pinebook Pro)!
## Installation
-We will build OpenOCD from sources, as packages from Linux distributions are most of the time outdated and do not support the NRF52 correctly.
+We will build OpenOCD from sources, as packages from Linux distributions are most of the time outdated and do not support the NRF52 properly.
- Fetch the sources from GIT, and build and install it:
@@ -27,7 +27,7 @@ sudo cp contrib/60-openocd.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
```
- - You can now plug your STLinkV2 in a USB port and run OpenOCD to see if it's working correctly:
+ - You can now plug your STLinkV2 into a USB port and run OpenOCD to see if it's working correctly:
```
$ openocd -f interface/stlink.cfg -f target/nrf52.cfg
@@ -63,7 +63,7 @@ gdb_breakpoint_override hard
source [find target/nrf52.cfg]
```
-This file specifies to OpenOCD which debugger and target it will be connected to..
+This file specifies to OpenOCD which debugger and target it will be connected to.
Then, we use various *user files* to use OpenOCD to flash InfiniTime binary files.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 809544c..aec6ce0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -445,9 +445,10 @@ list(APPEND SOURCE_FILES
displayapp/screens/settings/SettingWakeUp.cpp
displayapp/screens/settings/SettingDisplay.cpp
displayapp/screens/settings/SettingSteps.cpp
- displayapp/screens/settings/SettingPineTimeStyle.cpp
displayapp/screens/settings/SettingSetDate.cpp
displayapp/screens/settings/SettingSetTime.cpp
+ displayapp/screens/settings/SettingChimes.cpp
+ displayapp/screens/settings/SettingShakeThreshold.cpp
## Watch faces
displayapp/icons/bg_clock.c
@@ -611,6 +612,7 @@ list(APPEND RECOVERYLOADER_SOURCE_FILES
set(INCLUDE_FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h
BootloaderVersion.h
logging/Logger.h
logging/NrfLogger.h
@@ -709,6 +711,7 @@ set(INCLUDE_FILES
)
include_directories(
+ ${CMAKE_BINARY_DIR}/src # include generated files like Version.h
.
../
libs/
diff --git a/src/buttonhandler/ButtonHandler.cpp b/src/buttonhandler/ButtonHandler.cpp
index 02ee22c..3c2bc72 100644
--- a/src/buttonhandler/ButtonHandler.cpp
+++ b/src/buttonhandler/ButtonHandler.cpp
@@ -1,4 +1,4 @@
-#include "ButtonHandler.h"
+#include "buttonhandler/ButtonHandler.h"
using namespace Pinetime::Controllers;
diff --git a/src/buttonhandler/ButtonHandler.h b/src/buttonhandler/ButtonHandler.h
index 44b20f1..5802b99 100644
--- a/src/buttonhandler/ButtonHandler.h
+++ b/src/buttonhandler/ButtonHandler.h
@@ -1,6 +1,6 @@
#pragma once
-#include "ButtonActions.h"
+#include "buttonhandler/ButtonActions.h"
#include "systemtask/SystemTask.h"
#include <FreeRTOS.h>
#include <timers.h>
diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp
index 82df7b1..9a3f86f 100644
--- a/src/components/ble/BatteryInformationService.cpp
+++ b/src/components/ble/BatteryInformationService.cpp
@@ -17,7 +17,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte
characteristicDefinition {{.uuid = &batteryLevelUuid.u,
.access_cb = BatteryInformationServiceCallback,
.arg = this,
- .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
+ .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
.val_handle = &batteryLevelHandle},
{0}},
serviceDefinition {
diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp
index 3bf1ec8..d8510bd 100644
--- a/src/components/ble/NimbleController.cpp
+++ b/src/components/ble/NimbleController.cpp
@@ -134,9 +134,7 @@ void NimbleController::Init() {
RestoreBond();
- if (!ble_gap_adv_active() && !bleController.IsConnected()) {
- StartAdvertising();
- }
+ StartAdvertising();
}
void NimbleController::StartAdvertising() {
@@ -274,7 +272,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
* display capability only so we only handle the "display" action here.
*
* Standards insist that the rand() PRNG be deterministic.
- * Use the nimble TRNG here since rand() is predictable.
+ * Use the tinycrypt prng here since rand() is predictable.
*/
NRF_LOG_INFO("Security event : BLE_GAP_EVENT_PASSKEY_ACTION");
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h
index 7a38703..2b300e6 100644
--- a/src/components/ble/NimbleController.h
+++ b/src/components/ble/NimbleController.h
@@ -110,8 +110,8 @@ namespace Pinetime {
ImmediateAlertService immediateAlertService;
HeartRateService heartRateService;
MotionService motionService;
- ServiceDiscovery serviceDiscovery;
FSService fsService;
+ ServiceDiscovery serviceDiscovery;
uint8_t addrType;
uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;
diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp
index 4ac9e1f..673903c 100644
--- a/src/components/datetime/DateTimeController.cpp
+++ b/src/components/datetime/DateTimeController.cpp
@@ -75,6 +75,24 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
minute = time.minutes().count();
second = time.seconds().count();
+ if (minute == 0 && !isHourAlreadyNotified) {
+ isHourAlreadyNotified = true;
+ if (systemTask != nullptr) {
+ systemTask->PushMessage(System::Messages::OnNewHour);
+ }
+ } else if (minute != 0) {
+ isHourAlreadyNotified = false;
+ }
+
+ if ((minute == 0 || minute == 30) && !isHalfHourAlreadyNotified) {
+ isHalfHourAlreadyNotified = true;
+ if (systemTask != nullptr) {
+ systemTask->PushMessage(System::Messages::OnNewHalfHour);
+ }
+ } else if (minute != 0 && minute != 30) {
+ isHalfHourAlreadyNotified = false;
+ }
+
// Notify new day to SystemTask
if (hour == 0 and not isMidnightAlreadyNotified) {
isMidnightAlreadyNotified = true;
@@ -100,4 +118,3 @@ const char* DateTime::MonthShortToStringLow(Months month) {
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
this->systemTask = systemTask;
}
-
diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h
index 77ed68e..cbc8044 100644
--- a/src/components/datetime/DateTimeController.h
+++ b/src/components/datetime/DateTimeController.h
@@ -86,6 +86,8 @@ namespace Pinetime {
std::chrono::seconds uptime {0};
bool isMidnightAlreadyNotified = false;
+ bool isHourAlreadyNotified = true;
+ bool isHalfHourAlreadyNotified = true;
System::SystemTask* systemTask = nullptr;
};
}
diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp
index cae4910..7dd3212 100644
--- a/src/components/motion/MotionController.cpp
+++ b/src/components/motion/MotionController.cpp
@@ -1,5 +1,5 @@
#include "components/motion/MotionController.h"
-
+#include "os/os_cputime.h"
using namespace Pinetime::Controllers;
void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps) {
@@ -7,17 +7,21 @@ void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps)
service->OnNewStepCountValue(nbSteps);
}
- if(service != nullptr && (this->x != x || this->y != y || this->z != z)) {
+ if (service != nullptr && (this->x != x || this->y != y || this->z != z)) {
service->OnNewMotionValues(x, y, z);
}
this->x = x;
this->y = y;
this->z = z;
+ int32_t deltaSteps = nbSteps - this->nbSteps;
this->nbSteps = nbSteps;
+ if (deltaSteps > 0) {
+ currentTripSteps += deltaSteps;
+ }
}
-bool MotionController::ShouldWakeUp(bool isSleeping) {
+bool MotionController::Should_RaiseWake(bool isSleeping) {
if ((x + 335) <= 670 && z < 0) {
if (not isSleeping) {
if (y <= 0) {
@@ -39,14 +43,43 @@ bool MotionController::ShouldWakeUp(bool isSleeping) {
}
return false;
}
+
+bool MotionController::Should_ShakeWake(uint16_t thresh) {
+ bool wake = false;
+ auto diff = xTaskGetTickCount() - lastShakeTime;
+ lastShakeTime = xTaskGetTickCount();
+ /* Currently Polling at 10hz, If this ever goes faster scalar and EMA might need adjusting */
+ int32_t speed = std::abs(z + (y / 2) + (x / 4) - lastYForShake - lastZForShake) / diff * 100;
+ //(.2 * speed) + ((1 - .2) * accumulatedspeed);
+ // implemented without floats as .25Alpha
+ accumulatedspeed = (speed / 5) + ((accumulatedspeed / 5) * 4);
+
+ if (accumulatedspeed > thresh) {
+ wake = true;
+ }
+ lastXForShake = x / 4;
+ lastYForShake = y / 2;
+ lastZForShake = z;
+ return wake;
+}
+int32_t MotionController::currentShakeSpeed() {
+ return accumulatedspeed;
+}
+
void MotionController::IsSensorOk(bool isOk) {
isSensorOk = isOk;
}
void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) {
- switch(types){
- case Drivers::Bma421::DeviceTypes::BMA421: this->deviceType = DeviceTypes::BMA421; break;
- case Drivers::Bma421::DeviceTypes::BMA425: this->deviceType = DeviceTypes::BMA425; break;
- default: this->deviceType = DeviceTypes::Unknown; break;
+ switch (types) {
+ case Drivers::Bma421::DeviceTypes::BMA421:
+ this->deviceType = DeviceTypes::BMA421;
+ break;
+ case Drivers::Bma421::DeviceTypes::BMA425:
+ this->deviceType = DeviceTypes::BMA425;
+ break;
+ default:
+ this->deviceType = DeviceTypes::Unknown;
+ break;
}
}
void MotionController::SetService(Pinetime::Controllers::MotionService* service) {
diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h
index c72d8a4..f80b11b 100644
--- a/src/components/motion/MotionController.h
+++ b/src/components/motion/MotionController.h
@@ -8,7 +8,7 @@ namespace Pinetime {
namespace Controllers {
class MotionController {
public:
- enum class DeviceTypes{
+ enum class DeviceTypes {
Unknown,
BMA421,
BMA425,
@@ -28,8 +28,17 @@ namespace Pinetime {
uint32_t NbSteps() const {
return nbSteps;
}
- bool ShouldWakeUp(bool isSleeping);
+ void ResetTrip() {
+ currentTripSteps = 0;
+ }
+ uint32_t GetTripSteps() const {
+ return currentTripSteps;
+ }
+
+ bool Should_ShakeWake(uint16_t thresh);
+ bool Should_RaiseWake(bool isSleeping);
+ int32_t currentShakeSpeed();
void IsSensorOk(bool isOk);
bool IsSensorOk() const {
return isSensorOk;
@@ -44,6 +53,7 @@ namespace Pinetime {
private:
uint32_t nbSteps;
+ uint32_t currentTripSteps = 0;
int16_t x;
int16_t y;
int16_t z;
@@ -51,6 +61,12 @@ namespace Pinetime {
bool isSensorOk = false;
DeviceTypes deviceType = DeviceTypes::Unknown;
Pinetime::Controllers::MotionService* service = nullptr;
+
+ int16_t lastXForShake = 0;
+ int16_t lastYForShake = 0;
+ int16_t lastZForShake = 0;
+ int32_t accumulatedspeed = 0;
+ uint32_t lastShakeTime = 0;
};
}
} \ No newline at end of file
diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h
index 2d7973d..6de44aa 100644
--- a/src/components/settings/Settings.h
+++ b/src/components/settings/Settings.h
@@ -11,10 +11,12 @@ namespace Pinetime {
public:
enum class ClockType : uint8_t { H24, H12 };
enum class Notification : uint8_t { ON, OFF };
+ enum class ChimesOption : uint8_t { None, Hours, HalfHours };
enum class WakeUpMode : uint8_t {
SingleTap = 0,
DoubleTap = 1,
RaiseWrist = 2,
+ Shake = 3,
};
enum class Colors : uint8_t {
White, Silver, Gray, Black, Red, Maroon, Yellow, Olive, Lime, Green, Cyan, Teal, Blue, Navy, Magenta, Purple, Orange
@@ -40,6 +42,16 @@ namespace Pinetime {
return settings.clockFace;
};
+ void SetChimeOption(ChimesOption chimeOption) {
+ if (chimeOption != settings.chimesOption) {
+ settingsChanged = true;
+ }
+ settings.chimesOption = chimeOption;
+ };
+ ChimesOption GetChimeOption() const {
+ return settings.chimesOption;
+ };
+
void SetPTSColorTime(Colors colorTime) {
if (colorTime != settings.PTS.ColorTime)
settingsChanged = true;
@@ -108,10 +120,23 @@ namespace Pinetime {
}
settings.screenTimeOut = timeout;
};
+
uint32_t GetScreenTimeOut() const {
return settings.screenTimeOut;
};
+ void SetShakeThreshold(uint16_t thresh){
+ if(settings.shakeWakeThreshold != thresh){
+ settings.shakeWakeThreshold = thresh;
+ settingsChanged = true;
+ }
+
+ }
+
+ int16_t GetShakeThreshold() const{
+ return settings.shakeWakeThreshold;
+ }
+
void setWakeUpMode(WakeUpMode wakeUp, bool enabled) {
if (enabled != isWakeUpModeOn(wakeUp)) {
settingsChanged = true;
@@ -126,13 +151,13 @@ namespace Pinetime {
case WakeUpMode::DoubleTap:
settings.wakeUpMode.set(static_cast<size_t>(WakeUpMode::SingleTap), false);
break;
- case WakeUpMode::RaiseWrist:
+ default:
break;
}
}
};
- std::bitset<3> getWakeUpModes() const {
+ std::bitset<4> getWakeUpModes() const {
return settings.wakeUpMode;
}
@@ -162,7 +187,7 @@ namespace Pinetime {
private:
Pinetime::Controllers::FS& fs;
- static constexpr uint32_t settingsVersion = 0x0002;
+ static constexpr uint32_t settingsVersion = 0x0003;
struct SettingsData {
uint32_t version = settingsVersion;
uint32_t stepsGoal = 10000;
@@ -172,11 +197,12 @@ namespace Pinetime {
Notification notificationStatus = Notification::ON;
uint8_t clockFace = 0;
+ ChimesOption chimesOption = ChimesOption::None;
PineTimeStyle PTS;
- std::bitset<3> wakeUpMode {0};
-
+ std::bitset<4> wakeUpMode {0};
+ uint16_t shakeWakeThreshold = 150;
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
};
diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h
index b2f55cc..b876020 100644
--- a/src/displayapp/Apps.h
+++ b/src/displayapp/Apps.h
@@ -34,10 +34,11 @@ namespace Pinetime {
SettingDisplay,
SettingWakeUp,
SettingSteps,
- SettingPineTimeStyle,
SettingSetDate,
SettingSetTime,
- Error,
+ SettingChimes,
+ SettingShakeThreshold,
+ Error
};
}
}
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index 233f433..cc544fd 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -45,9 +45,10 @@
#include "displayapp/screens/settings/SettingWakeUp.h"
#include "displayapp/screens/settings/SettingDisplay.h"
#include "displayapp/screens/settings/SettingSteps.h"
-#include "displayapp/screens/settings/SettingPineTimeStyle.h"
#include "displayapp/screens/settings/SettingSetDate.h"
#include "displayapp/screens/settings/SettingSetTime.h"
+#include "displayapp/screens/settings/SettingChimes.h"
+#include "displayapp/screens/settings/SettingShakeThreshold.h"
#include "libs/lv_conf.h"
@@ -255,10 +256,10 @@ void DisplayApp::Refresh() {
}
} break;
case Messages::ButtonPushed:
- if (currentApp == Apps::Clock) {
- PushMessageToSystemTask(System::Messages::GoToSleep);
- } else {
- if (!currentScreen->OnButtonPushed()) {
+ if (!currentScreen->OnButtonPushed()) {
+ if (currentApp == Apps::Clock) {
+ PushMessageToSystemTask(System::Messages::GoToSleep);
+ } else {
LoadApp(returnToApp, returnDirection);
brightnessController.Set(settingsController.GetBrightness());
brightnessController.Backup();
@@ -293,6 +294,9 @@ void DisplayApp::Refresh() {
// Added to remove warning
// What should happen here?
break;
+ case Messages::Clock:
+ LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
+ break;
}
}
@@ -363,12 +367,12 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
case Apps::Notifications:
currentScreen = std::make_unique<Screens::Notifications>(
- this, notificationManager, systemTask->nimble().alertService(), motorController, Screens::Notifications::Modes::Normal);
+ this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Normal);
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
break;
case Apps::NotificationsPreview:
currentScreen = std::make_unique<Screens::Notifications>(
- this, notificationManager, systemTask->nimble().alertService(), motorController, Screens::Notifications::Modes::Preview);
+ this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Preview);
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
break;
case Apps::Timer:
@@ -416,8 +420,12 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
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);
+ case Apps::SettingChimes:
+ currentScreen = std::make_unique<Screens::SettingChimes>(this, settingsController);
+ ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
+ case Apps::SettingShakeThreshold:
+ currentScreen = std::make_unique<Screens::SettingShakeThreshold>(this, settingsController,motionController,*systemTask);
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::BatteryInfo:
diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h
index b22d6c3..a3a78cc 100644
--- a/src/displayapp/Messages.h
+++ b/src/displayapp/Messages.h
@@ -20,7 +20,8 @@ namespace Pinetime {
DimScreen,
RestoreBrightness,
ShowPairingKey,
- AlarmTriggered
+ AlarmTriggered,
+ Clock
};
}
}
diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp
index 96d8e5b..1415e8e 100644
--- a/src/displayapp/screens/Clock.cpp
+++ b/src/displayapp/screens/Clock.cpp
@@ -55,6 +55,10 @@ bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screen->OnTouchEvent(event);
}
+bool Clock::OnButtonPushed() {
+ return screen->OnButtonPushed();
+}
+
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
return std::make_unique<Screens::WatchFaceDigital>(app,
dateTimeController,
diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h
index 2fad1e2..fcecc6b 100644
--- a/src/displayapp/screens/Clock.h
+++ b/src/displayapp/screens/Clock.h
@@ -32,6 +32,7 @@ namespace Pinetime {
~Clock() override;
bool OnTouchEvent(TouchEvents event) override;
+ bool OnButtonPushed() override;
private:
Controllers::DateTime& dateTimeController;
diff --git a/src/displayapp/screens/InfiniPaint.cpp b/src/displayapp/screens/InfiniPaint.cpp
index 93c3c4a..d279faf 100644
--- a/src/displayapp/screens/InfiniPaint.cpp
+++ b/src/displayapp/screens/InfiniPaint.cpp
@@ -2,6 +2,8 @@
#include "displayapp/DisplayApp.h"
#include "displayapp/LittleVgl.h"
+#include <algorithm> // std::fill
+
using namespace Pinetime::Applications::Screens;
InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app,
diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp
index 8347e1b..f6f269d 100644
--- a/src/displayapp/screens/Metronome.cpp
+++ b/src/displayapp/screens/Metronome.cpp
@@ -113,9 +113,16 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
}
tappedTime = xTaskGetTickCount();
+ allowExit = true;
}
break;
}
+ case LV_EVENT_RELEASED:
+ case LV_EVENT_PRESS_LOST:
+ if (obj == bpmTap) {
+ allowExit = false;
+ }
+ break;
case LV_EVENT_CLICKED: {
if (obj == playPause) {
metronomeStarted = !metronomeStarted;
@@ -135,3 +142,11 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
break;
}
}
+
+bool Metronome::OnTouchEvent(TouchEvents event) {
+ if (event == TouchEvents::SwipeDown && allowExit) {
+ running = false;
+ return true;
+ }
+ return false;
+}
diff --git a/src/displayapp/screens/Metronome.h b/src/displayapp/screens/Metronome.h
index 373c884..6e6589f 100644
--- a/src/displayapp/screens/Metronome.h
+++ b/src/displayapp/screens/Metronome.h
@@ -14,6 +14,7 @@ namespace Pinetime {
~Metronome() override;
void Refresh() override;
void OnEvent(lv_obj_t* obj, lv_event_t event);
+ bool OnTouchEvent(TouchEvents event) override;
private:
TickType_t startTime = 0;
@@ -25,6 +26,7 @@ namespace Pinetime {
uint8_t counter = 1;
bool metronomeStarted = false;
+ bool allowExit = false;
lv_obj_t *bpmArc, *bpmTap, *bpmValue;
lv_obj_t *bpbDropdown, *currentBpbText;
diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 8a01a6f..9f17b95 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -277,12 +277,14 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return true;
}
case TouchEvents::SwipeDown: {
- lv_obj_set_hidden(btnNext, false);
- lv_obj_set_hidden(btnPrev, false);
-
- lv_obj_set_hidden(btnVolDown, true);
- lv_obj_set_hidden(btnVolUp, true);
- return true;
+ if (lv_obj_get_hidden(btnNext)) {
+ lv_obj_set_hidden(btnNext, false);
+ lv_obj_set_hidden(btnPrev, false);
+ lv_obj_set_hidden(btnVolDown, true);
+ lv_obj_set_hidden(btnVolUp, true);
+ return true;
+ }
+ return false;
}
case TouchEvents::SwipeLeft: {
musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT);
diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp
index 569c422..8fe08a8 100644
--- a/src/displayapp/screens/Notifications.cpp
+++ b/src/displayapp/screens/Notifications.cpp
@@ -12,8 +12,13 @@ Notifications::Notifications(DisplayApp* app,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController,
+ System::SystemTask& systemTask,
Modes mode)
- : Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, mode {mode} {
+ : Screen(app),
+ notificationManager {notificationManager},
+ alertNotificationService {alertNotificationService},
+ systemTask {systemTask},
+ mode {mode} {
notificationManager.ClearNewNotificationFlag();
auto notification = notificationManager.GetLastNotification();
if (notification.valid) {
@@ -37,20 +42,22 @@ Notifications::Notifications(DisplayApp* app,
}
if (mode == Modes::Preview) {
+ systemTask.PushMessage(System::Messages::DisableSleeping);
if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) {
motorController.StartRinging();
} else {
motorController.RunForDuration(35);
- timeoutLine = lv_line_create(lv_scr_act(), nullptr);
+ }
- lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
- lv_obj_set_style_local_line_color(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
- lv_obj_set_style_local_line_rounded(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
+ timeoutLine = lv_line_create(lv_scr_act(), nullptr);
- lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
- timeoutTickCountStart = xTaskGetTickCount();
- timeoutTickCountEnd = timeoutTickCountStart + (5 * 1024);
- }
+ lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
+ lv_obj_set_style_local_line_color(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_line_rounded(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
+
+ lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
+ timeoutTickCountStart = xTaskGetTickCount();
+ interacted = false;
}
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
@@ -60,23 +67,40 @@ Notifications::~Notifications() {
lv_task_del(taskRefresh);
// make sure we stop any vibrations before exiting
Controllers::MotorController::StopRinging();
+ systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
void Notifications::Refresh() {
if (mode == Modes::Preview && timeoutLine != nullptr) {
- auto tick = xTaskGetTickCount();
- int32_t pos = 240 - ((tick - timeoutTickCountStart) / ((timeoutTickCountEnd - timeoutTickCountStart) / 240));
- if (pos < 0)
+ TickType_t tick = xTaskGetTickCount();
+ int32_t pos = 240 - ((tick - timeoutTickCountStart) / (timeoutLength / 240));
+ if (pos <= 0) {
running = false;
+ } else {
+ timeoutLinePoints[1].x = pos;
+ lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
+ }
+ }
+ running = currentItem->IsRunning() && running;
+}
- timeoutLinePoints[1].x = pos;
- lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
+void Notifications::OnPreviewInteraction() {
+ systemTask.PushMessage(System::Messages::EnableSleeping);
+ Controllers::MotorController::StopRinging();
+ if (timeoutLine != nullptr) {
+ lv_obj_del(timeoutLine);
+ timeoutLine = nullptr;
}
}
bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
if (mode != Modes::Normal) {
+ if (!interacted && event == TouchEvents::Tap) {
+ interacted = true;
+ OnPreviewInteraction();
+ return true;
+ }
return false;
}
diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h
index cbb7af6..2f444c7 100644
--- a/src/displayapp/screens/Notifications.h
+++ b/src/displayapp/screens/Notifications.h
@@ -1,11 +1,13 @@
#pragma once
#include <lvgl/lvgl.h>
+#include <FreeRTOS.h>
#include <cstdint>
#include <memory>
#include "displayapp/screens/Screen.h"
#include "components/ble/NotificationManager.h"
#include "components/motor/MotorController.h"
+#include "systemtask/SystemTask.h"
namespace Pinetime {
namespace Controllers {
@@ -21,11 +23,13 @@ namespace Pinetime {
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController,
+ System::SystemTask& systemTask,
Modes mode);
~Notifications() override;
void Refresh() override;
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
+ void OnPreviewInteraction();
class NotificationItem {
public:
@@ -62,6 +66,7 @@ namespace Pinetime {
};
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
+ System::SystemTask& systemTask;
Modes mode = Modes::Normal;
std::unique_ptr<NotificationItem> currentItem;
Controllers::NotificationManager::Notification::Id currentId;
@@ -69,8 +74,9 @@ namespace Pinetime {
lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}};
lv_obj_t* timeoutLine = nullptr;
- uint32_t timeoutTickCountStart;
- uint32_t timeoutTickCountEnd;
+ TickType_t timeoutTickCountStart;
+ static const TickType_t timeoutLength = pdMS_TO_TICKS(7000);
+ bool interacted = true;
lv_task_t* taskRefresh;
};
diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp
index d436869..7ce0bc0 100644
--- a/src/displayapp/screens/PineTimeStyle.cpp
+++ b/src/displayapp/screens/PineTimeStyle.cpp
@@ -37,6 +37,13 @@
using namespace Pinetime::Applications::Screens;
+namespace {
+ void event_handler(lv_obj_t* obj, lv_event_t event) {
+ auto* screen = static_cast<PineTimeStyle*>(obj->user_data);
+ screen->UpdateSelected(obj, event);
+ }
+}
+
PineTimeStyle::PineTimeStyle(DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController,
@@ -53,16 +60,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
settingsController {settingsController},
motionController {motionController} {
- // This sets the watchface number to return to after leaving the menu
- settingsController.SetClockFace(2);
-
- displayedChar[0] = 0;
- displayedChar[1] = 0;
- displayedChar[2] = 0;
- displayedChar[3] = 0;
- displayedChar[4] = 0;
-
- //Create a 200px wide background rectangle
+ // Create a 200px wide background rectangle
timebar = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBG()));
lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
@@ -73,19 +71,19 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
timeDD1 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
- lv_label_set_text(timeDD1, "00");
+ lv_label_set_text_static(timeDD1, "00");
lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
timeDD2 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
- lv_label_set_text(timeDD2, "00");
+ lv_label_set_text_static(timeDD2, "00");
lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
timeAMPM = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3);
- lv_label_set_text(timeAMPM, "");
+ lv_label_set_text_static(timeAMPM, "");
lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20);
// Create a 40px wide bar down the right side of the screen
@@ -97,74 +95,78 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
// Display icons
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(batteryIcon, Symbols::batteryFull);
+ lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_label_set_text_static(batteryIcon, Symbols::batteryFull);
lv_obj_align(batteryIcon, 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));
- lv_label_set_text(bleIcon, "");
+ lv_label_set_text_static(bleIcon, "");
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(notificationIcon, "");
+ lv_label_set_text_static(notificationIcon, "");
// Calendar icon
calendarOuter = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarOuter, 34, 34);
lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
calendarInner = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
+ lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_radius(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarInner, 27, 27);
lv_obj_align(calendarInner, calendarOuter, LV_ALIGN_CENTER, 0, 0);
calendarBar1 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_bg_color(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_radius(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarBar1, 3, 12);
lv_obj_align(calendarBar1, calendarOuter, LV_ALIGN_IN_TOP_MID, -6, -3);
calendarBar2 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_bg_color(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_radius(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarBar2, 3, 12);
lv_obj_align(calendarBar2, calendarOuter, LV_ALIGN_IN_TOP_MID, 6, -3);
calendarCrossBar1 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_bg_color(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_radius(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarCrossBar1, 8, 3);
lv_obj_align(calendarCrossBar1, calendarBar1, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
calendarCrossBar2 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
+ lv_obj_set_style_local_bg_color(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_radius(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarCrossBar2, 8, 3);
lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
// Display date
dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(dateDayOfWeek, "THU");
+ lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_label_set_text_static(dateDayOfWeek, "THU");
lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34);
dateDay = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(dateDay, "25");
+ lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_label_set_text_static(dateDay, "25");
lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3);
dateMonth = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(dateMonth, "MAR");
+ lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_label_set_text_static(dateMonth, "MAR");
lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32);
// Step count gauge
- needle_colors[0] = LV_COLOR_WHITE;
+ if (settingsController.GetPTSColorBar() == Pinetime::Controllers::Settings::Colors::White) {
+ needle_colors[0] = LV_COLOR_BLACK;
+ } else {
+ needle_colors[0] = LV_COLOR_WHITE;
+ }
stepGauge = lv_gauge_create(lv_scr_act(), nullptr);
lv_gauge_set_needle_count(stepGauge, 1, needle_colors);
lv_obj_set_size(stepGauge, 40, 40);
@@ -191,7 +193,101 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app,
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
- lv_label_set_text(backgroundLabel, "");
+ lv_label_set_text_static(backgroundLabel, "");
+
+ btnNextTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnNextTime->user_data = this;
+ lv_obj_set_size(btnNextTime, 60, 60);
+ lv_obj_align(btnNextTime, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, -80);
+ lv_obj_set_style_local_bg_opa(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
+ lv_obj_set_event_cb(btnNextTime, event_handler);
+ lv_obj_set_hidden(btnNextTime, true);
+
+ btnPrevTime = lv_btn_create(lv_scr_act(), nullptr);
+ btnPrevTime->user_data = this;
+ lv_obj_set_size(btnPrevTime, 60, 60);
+ lv_obj_align(btnPrevTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, -80);
+ lv_obj_set_style_local_bg_opa(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
+ lv_obj_set_event_cb(btnPrevTime, event_handler);
+ lv_obj_set_hidden(btnPrevTime, true);
+
+ btnNextBar = lv_btn_create(lv_scr_act(), nullptr);
+ btnNextBar->user_data = this;
+ lv_obj_set_size(btnNextBar, 60, 60);
+ lv_obj_align(btnNextBar, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0);
+ lv_obj_set_style_local_bg_opa(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
+ lv_obj_set_event_cb(btnNextBar, event_handler);
+ lv_obj_set_hidden(btnNextBar, true);
+
+ btnPrevBar = lv_btn_create(lv_scr_act(), nullptr);
+ btnPrevBar->user_data = this;
+ lv_obj_set_size(btnPrevBar, 60, 60);
+ lv_obj_align(btnPrevBar, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0);
+ lv_obj_set_style_local_bg_opa(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
+ lv_obj_set_event_cb(btnPrevBar, event_handler);
+ lv_obj_set_hidden(btnPrevBar, true);
+
+ btnNextBG = lv_btn_create(lv_scr_act(), nullptr);
+ btnNextBG->user_data = this;
+ lv_obj_set_size(btnNextBG, 60, 60);
+ lv_obj_align(btnNextBG, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 80);
+ lv_obj_set_style_local_bg_opa(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
+ lv_obj_set_event_cb(btnNextBG, event_handler);
+ lv_obj_set_hidden(btnNextBG, true);
+
+ btnPrevBG = lv_btn_create(lv_scr_act(), nullptr);
+ btnPrevBG->user_data = this;
+ lv_obj_set_size(btnPrevBG, 60, 60);
+ lv_obj_align(btnPrevBG, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 80);
+ lv_obj_set_style_local_bg_opa(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
+ lv_obj_set_event_cb(btnPrevBG, event_handler);
+ lv_obj_set_hidden(btnPrevBG, true);
+
+ btnReset = lv_btn_create(lv_scr_act(), nullptr);
+ btnReset->user_data = this;
+ lv_obj_set_size(btnReset, 60, 60);
+ lv_obj_align(btnReset, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
+ lv_obj_set_style_local_bg_opa(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rst");
+ lv_obj_set_event_cb(btnReset, event_handler);
+ lv_obj_set_hidden(btnReset, true);
+
+ btnRandom = lv_btn_create(lv_scr_act(), nullptr);
+ btnRandom->user_data = this;
+ lv_obj_set_size(btnRandom, 60, 60);
+ lv_obj_align(btnRandom, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_bg_opa(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rnd");
+ lv_obj_set_event_cb(btnRandom, event_handler);
+ lv_obj_set_hidden(btnRandom, true);
+
+ btnClose = lv_btn_create(lv_scr_act(), nullptr);
+ btnClose->user_data = this;
+ lv_obj_set_size(btnClose, 60, 60);
+ lv_obj_align(btnClose, lv_scr_act(), LV_ALIGN_CENTER, 0, -80);
+ lv_obj_set_style_local_bg_opa(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_style_local_value_str(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "X");
+ lv_obj_set_event_cb(btnClose, event_handler);
+ lv_obj_set_hidden(btnClose, true);
+
+ btnSet = lv_btn_create(lv_scr_act(), nullptr);
+ btnSet->user_data = this;
+ lv_obj_set_height(btnSet, 150);
+ lv_obj_set_width(btnSet, 150);
+ lv_obj_align(btnSet, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_radius(btnSet, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 30);
+ lv_obj_set_style_local_bg_opa(btnSet, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_set_event_cb(btnSet, event_handler);
+ lbl_btnSet = lv_label_create(btnSet, nullptr);
+ lv_obj_set_style_local_text_font(lbl_btnSet, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
+ lv_label_set_text_static(lbl_btnSet, Symbols::settings);
+ lv_obj_set_hidden(btnSet, true);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
@@ -202,9 +298,42 @@ PineTimeStyle::~PineTimeStyle() {
lv_obj_clean(lv_scr_act());
}
+bool PineTimeStyle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
+ if ((event == Pinetime::Applications::TouchEvents::LongTap) && lv_obj_get_hidden(btnRandom)) {
+ lv_obj_set_hidden(btnSet, false);
+ savedTick = lv_tick_get();
+ return true;
+ }
+ if ((event == Pinetime::Applications::TouchEvents::DoubleTap) && (lv_obj_get_hidden(btnRandom) == false)) {
+ return true;
+ }
+ return false;
+}
+
+void PineTimeStyle::CloseMenu() {
+ settingsController.SaveSettings();
+ lv_obj_set_hidden(btnNextTime, true);
+ lv_obj_set_hidden(btnPrevTime, true);
+ lv_obj_set_hidden(btnNextBar, true);
+ lv_obj_set_hidden(btnPrevBar, true);
+ lv_obj_set_hidden(btnNextBG, true);
+ lv_obj_set_hidden(btnPrevBG, true);
+ lv_obj_set_hidden(btnReset, true);
+ lv_obj_set_hidden(btnRandom, true);
+ lv_obj_set_hidden(btnClose, true);
+}
+
+bool PineTimeStyle::OnButtonPushed() {
+ if (!lv_obj_get_hidden(btnClose)) {
+ CloseMenu();
+ return true;
+ }
+ return false;
+}
+
void PineTimeStyle::SetBatteryIcon() {
auto batteryPercent = batteryPercentRemaining.Get();
- lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
+ lv_label_set_text_static(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
}
void PineTimeStyle::AlignIcons() {
@@ -222,7 +351,7 @@ void PineTimeStyle::Refresh() {
isCharging = batteryController.IsCharging();
if (isCharging.IsUpdated()) {
if (isCharging.Get()) {
- lv_label_set_text(batteryIcon, Symbols::plug);
+ lv_label_set_text_static(batteryIcon, Symbols::plug);
} else {
SetBatteryIcon();
}
@@ -236,13 +365,13 @@ void PineTimeStyle::Refresh() {
bleState = bleController.IsConnected();
if (bleState.IsUpdated()) {
- lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get()));
+ lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
AlignIcons();
}
notificationState = notificatioManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
- lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
+ lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
AlignIcons();
}
@@ -259,45 +388,31 @@ void PineTimeStyle::Refresh() {
auto day = static_cast<unsigned>(yearMonthDay.day());
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
- int hour = time.hours().count();
- auto minute = time.minutes().count();
+ uint8_t hour = time.hours().count();
+ uint8_t minute = time.minutes().count();
- char minutesChar[3];
- sprintf(minutesChar, "%02d", static_cast<int>(minute));
-
- char hoursChar[3];
- char ampmChar[5];
- if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
- sprintf(hoursChar, "%02d", hour);
- } else {
- if (hour == 0 && hour != 12) {
- hour = 12;
- sprintf(ampmChar, "A\nM");
- } else if (hour == 12 && hour != 0) {
- hour = 12;
- sprintf(ampmChar, "P\nM");
- } else if (hour < 12 && hour != 0) {
- sprintf(ampmChar, "A\nM");
- } else if (hour > 12 && hour != 0) {
- hour = hour - 12;
- sprintf(ampmChar, "P\nM");
- }
- sprintf(hoursChar, "%02d", hour);
- }
-
- if (hoursChar[0] != displayedChar[0] or hoursChar[1] != displayedChar[1] or minutesChar[0] != displayedChar[2] or
- minutesChar[1] != displayedChar[3]) {
- displayedChar[0] = hoursChar[0];
- displayedChar[1] = hoursChar[1];
- displayedChar[2] = minutesChar[0];
- displayedChar[3] = minutesChar[1];
+ if (displayedHour != hour || displayedMinute != minute) {
+ displayedHour = hour;
+ displayedMinute = minute;
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
+ char ampmChar[4] = "A\nM";
+ if (hour == 0) {
+ hour = 12;
+ } else if (hour == 12) {
+ ampmChar[0] = 'P';
+ } else if (hour > 12) {
+ hour = hour - 12;
+ ampmChar[0] = 'P';
+ }
lv_label_set_text(timeAMPM, ampmChar);
+ // Should be padded with blank spaces, but the space character doesn't exist in the font
+ lv_label_set_text_fmt(timeDD1, "%02d", hour);
+ lv_label_set_text_fmt(timeDD2, "%02d", minute);
+ } else {
+ lv_label_set_text_fmt(timeDD1, "%02d", hour);
+ lv_label_set_text_fmt(timeDD2, "%02d", minute);
}
-
- lv_label_set_text_fmt(timeDD1, "%s", hoursChar);
- lv_label_set_text_fmt(timeDD2, "%s", minutesChar);
}
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
@@ -323,4 +438,154 @@ void PineTimeStyle::Refresh() {
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
}
+ if (!lv_obj_get_hidden(btnSet)) {
+ if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) {
+ lv_obj_set_hidden(btnSet, true);
+ savedTick = 0;
+ }
+ }
+}
+
+void PineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event) {
+ auto valueTime = settingsController.GetPTSColorTime();
+ auto valueBar = settingsController.GetPTSColorBar();
+ auto valueBG = settingsController.GetPTSColorBG();
+
+ if (event == LV_EVENT_CLICKED) {
+ if (object == btnNextTime) {
+ valueTime = GetNext(valueTime);
+ if (valueTime == valueBG) {
+ valueTime = GetNext(valueTime);
+ }
+ settingsController.SetPTSColorTime(valueTime);
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ }
+ if (object == btnPrevTime) {
+ valueTime = GetPrevious(valueTime);
+ if (valueTime == valueBG) {
+ valueTime = GetPrevious(valueTime);
+ }
+ settingsController.SetPTSColorTime(valueTime);
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ }
+ if (object == btnNextBar) {
+ valueBar = GetNext(valueBar);
+ if (valueBar == Controllers::Settings::Colors::Black) {
+ valueBar = GetNext(valueBar);
+ }
+ if (valueBar == Controllers::Settings::Colors::White) {
+ needle_colors[0] = LV_COLOR_BLACK;
+ } else {
+ needle_colors[0] = LV_COLOR_WHITE;
+ }
+ settingsController.SetPTSColorBar(valueBar);
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
+ }
+ if (object == btnPrevBar) {
+ valueBar = GetPrevious(valueBar);
+ if (valueBar == Controllers::Settings::Colors::Black) {
+ valueBar = GetPrevious(valueBar);
+ }
+ if (valueBar == Controllers::Settings::Colors::White) {
+ needle_colors[0] = LV_COLOR_BLACK;
+ } else {
+ needle_colors[0] = LV_COLOR_WHITE;
+ }
+ settingsController.SetPTSColorBar(valueBar);
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
+ }
+ if (object == btnNextBG) {
+ valueBG = GetNext(valueBG);
+ if (valueBG == valueTime) {
+ valueBG = GetNext(valueBG);
+ }
+ settingsController.SetPTSColorBG(valueBG);
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
+ }
+ if (object == btnPrevBG) {
+ valueBG = GetPrevious(valueBG);
+ if (valueBG == valueTime) {
+ valueBG = GetPrevious(valueBG);
+ }
+ settingsController.SetPTSColorBG(valueBG);
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
+ }
+ if (object == btnReset) {
+ needle_colors[0] = LV_COLOR_WHITE;
+ settingsController.SetPTSColorTime(Controllers::Settings::Colors::Teal);
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ settingsController.SetPTSColorBar(Controllers::Settings::Colors::Teal);
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
+ settingsController.SetPTSColorBG(Controllers::Settings::Colors::Black);
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Black));
+ }
+ if (object == btnRandom) {
+ valueTime = static_cast<Controllers::Settings::Colors>(rand() % 17);
+ valueBar = static_cast<Controllers::Settings::Colors>(rand() % 17);
+ valueBG = static_cast<Controllers::Settings::Colors>(rand() % 17);
+ if (valueTime == valueBG) {
+ valueBG = GetNext(valueBG);
+ }
+ if (valueBar == Controllers::Settings::Colors::Black) {
+ valueBar = GetPrevious(valueBar);
+ }
+ if (valueBar == Controllers::Settings::Colors::White) {
+ needle_colors[0] = LV_COLOR_BLACK;
+ } else {
+ needle_colors[0] = LV_COLOR_WHITE;
+ }
+ settingsController.SetPTSColorTime(static_cast<Controllers::Settings::Colors>(valueTime));
+ lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
+ settingsController.SetPTSColorBar(static_cast<Controllers::Settings::Colors>(valueBar));
+ lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
+ settingsController.SetPTSColorBG(static_cast<Controllers::Settings::Colors>(valueBG));
+ lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
+ }
+ if (object == btnClose) {
+ CloseMenu();
+ }
+ if (object == btnSet) {
+ lv_obj_set_hidden(btnSet, true);
+ lv_obj_set_hidden(btnNextTime, false);
+ lv_obj_set_hidden(btnPrevTime, false);
+ lv_obj_set_hidden(btnNextBar, false);
+ lv_obj_set_hidden(btnPrevBar, false);
+ lv_obj_set_hidden(btnNextBG, false);
+ lv_obj_set_hidden(btnPrevBG, false);
+ lv_obj_set_hidden(btnReset, false);
+ lv_obj_set_hidden(btnRandom, false);
+ lv_obj_set_hidden(btnClose, false);
+ }
+ }
+}
+
+Pinetime::Controllers::Settings::Colors PineTimeStyle::GetNext(Pinetime::Controllers::Settings::Colors color) {
+ auto colorAsInt = static_cast<uint8_t>(color);
+ Pinetime::Controllers::Settings::Colors nextColor;
+ if (colorAsInt < 16) {
+ nextColor = static_cast<Controllers::Settings::Colors>(colorAsInt + 1);
+ } else {
+ nextColor = static_cast<Controllers::Settings::Colors>(0);
+ }
+ return nextColor;
+}
+
+Pinetime::Controllers::Settings::Colors PineTimeStyle::GetPrevious(Pinetime::Controllers::Settings::Colors color) {
+ auto colorAsInt = static_cast<uint8_t>(color);
+ Pinetime::Controllers::Settings::Colors prevColor;
+
+ if (colorAsInt > 0) {
+ prevColor = static_cast<Controllers::Settings::Colors>(colorAsInt - 1);
+ } else {
+ prevColor = static_cast<Controllers::Settings::Colors>(16);
+ }
+ return prevColor;
}
diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h
index 8382c53..1b972ce 100644
--- a/src/displayapp/screens/PineTimeStyle.h
+++ b/src/displayapp/screens/PineTimeStyle.h
@@ -5,6 +5,7 @@
#include <cstdint>
#include <memory>
#include "displayapp/screens/Screen.h"
+#include "displayapp/Colors.h"
#include "components/datetime/DateTimeController.h"
namespace Pinetime {
@@ -30,15 +31,22 @@ namespace Pinetime {
Controllers::MotionController& motionController);
~PineTimeStyle() override;
+ bool OnTouchEvent(TouchEvents event) override;
+ bool OnButtonPushed() override;
+
void Refresh() override;
+ void UpdateSelected(lv_obj_t *object, lv_event_t event);
+
private:
- char displayedChar[5];
+ uint8_t displayedHour = -1;
+ uint8_t displayedMinute = -1;
uint16_t currentYear = 1970;
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
uint8_t currentDay = 0;
+ uint32_t savedTick = 0;
DirtyValue<uint8_t> batteryPercentRemaining {};
DirtyValue<bool> isCharging {};
@@ -48,6 +56,18 @@ namespace Pinetime {
DirtyValue<uint32_t> stepCount {};
DirtyValue<bool> notificationState {};
+ static Pinetime::Controllers::Settings::Colors GetNext(Controllers::Settings::Colors color);
+ static Pinetime::Controllers::Settings::Colors GetPrevious(Controllers::Settings::Colors color);
+
+ lv_obj_t* btnNextTime;
+ lv_obj_t* btnPrevTime;
+ lv_obj_t* btnNextBar;
+ lv_obj_t* btnPrevBar;
+ lv_obj_t* btnNextBG;
+ lv_obj_t* btnPrevBG;
+ lv_obj_t* btnReset;
+ lv_obj_t* btnRandom;
+ lv_obj_t* btnClose;
lv_obj_t* timebar;
lv_obj_t* sidebar;
lv_obj_t* timeDD1;
@@ -67,6 +87,8 @@ namespace Pinetime {
lv_obj_t* calendarCrossBar2;
lv_obj_t* notificationIcon;
lv_obj_t* stepGauge;
+ lv_obj_t* btnSet;
+ lv_obj_t* lbl_btnSet;
lv_color_t needle_colors[1];
Controllers::DateTime& dateTimeController;
@@ -77,6 +99,7 @@ namespace Pinetime {
Controllers::MotionController& motionController;
void SetBatteryIcon();
+ void CloseMenu();
void AlignIcons();
lv_task_t* taskRefresh;
diff --git a/src/displayapp/screens/Steps.cpp b/src/displayapp/screens/Steps.cpp
index 916138e..3e7f820 100644
--- a/src/displayapp/screens/Steps.cpp
+++ b/src/displayapp/screens/Steps.cpp
@@ -5,6 +5,11 @@
using namespace Pinetime::Applications::Screens;
+static void lap_event_handler(lv_obj_t* obj, lv_event_t event) {
+ auto* steps = static_cast<Steps*>(obj->user_data);
+ steps->lapBtnEventHandler(event);
+}
+
Steps::Steps(Pinetime::Applications::DisplayApp* app,
Controllers::MotionController& motionController,
Controllers::Settings& settingsController)
@@ -17,11 +22,12 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0x0000FF));
lv_arc_set_end_angle(stepsArc, 200);
- lv_obj_set_size(stepsArc, 220, 220);
+ lv_obj_set_size(stepsArc, 240, 240);
lv_arc_set_range(stepsArc, 0, 500);
lv_obj_align(stepsArc, nullptr, LV_ALIGN_CENTER, 0, 0);
stepsCount = motionController.NbSteps();
+ currentTripSteps = stepsCount - motionController.GetTripSteps();
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
@@ -29,18 +35,18 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
lv_obj_set_style_local_text_font(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
- lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
+ lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -40);
lv_obj_t* lstepsL = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lstepsL, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_label_set_text_static(lstepsL, "Steps");
- lv_obj_align(lstepsL, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
+ lv_obj_align(lstepsL, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
lv_obj_t* lstepsGoal = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lstepsGoal, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
- lv_label_set_text_fmt(lstepsGoal, "Goal\n%lu", settingsController.GetStepsGoal());
+ lv_label_set_text_fmt(lstepsGoal, "Goal: %5lu", settingsController.GetStepsGoal());
lv_label_set_align(lstepsGoal, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(lstepsGoal, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 60);
+ lv_obj_align(lstepsGoal, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 40);
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
@@ -48,6 +54,22 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
+ resetBtn = lv_btn_create(lv_scr_act(), nullptr);
+ resetBtn->user_data = this;
+ lv_obj_set_event_cb(resetBtn, lap_event_handler);
+ lv_obj_set_height(resetBtn, 50);
+ lv_obj_set_width(resetBtn, 115);
+ lv_obj_align(resetBtn, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ resetButtonLabel = lv_label_create(resetBtn, nullptr);
+ lv_label_set_text(resetButtonLabel, "Reset");
+
+ currentTripSteps = motionController.GetTripSteps();
+
+ tripLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(tripLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
+ lv_label_set_text_fmt(tripLabel, "Trip: %5li", currentTripSteps);
+ lv_obj_align(tripLabel, lstepsGoal, LV_ALIGN_IN_LEFT_MID, 0, 20);
+
taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
}
@@ -58,9 +80,24 @@ Steps::~Steps() {
void Steps::Refresh() {
stepsCount = motionController.NbSteps();
+ currentTripSteps = motionController.GetTripSteps();
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
- lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
+ lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -40);
+ if (currentTripSteps < 100000) {
+ lv_label_set_text_fmt(tripLabel, "Trip: %5li", currentTripSteps);
+ } else {
+ lv_label_set_text_fmt(tripLabel, "Trip: 99999+");
+ }
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
}
+
+void Steps::lapBtnEventHandler(lv_event_t event) {
+ if (event != LV_EVENT_CLICKED) {
+ return;
+ }
+ stepsCount = motionController.NbSteps();
+ motionController.ResetTrip();
+ Refresh();
+}
diff --git a/src/displayapp/screens/Steps.h b/src/displayapp/screens/Steps.h
index 68daf16..f109e0f 100644
--- a/src/displayapp/screens/Steps.h
+++ b/src/displayapp/screens/Steps.h
@@ -20,14 +20,20 @@ namespace Pinetime {
~Steps() override;
void Refresh() override;
+ void lapBtnEventHandler(lv_event_t event);
private:
Controllers::MotionController& motionController;
Controllers::Settings& settingsController;
+ uint32_t currentTripSteps = 0;
+
lv_obj_t* lSteps;
lv_obj_t* lStepsIcon;
lv_obj_t* stepsArc;
+ lv_obj_t* resetBtn;
+ lv_obj_t* resetButtonLabel;
+ lv_obj_t* tripLabel;
uint32_t stepsCount;
diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp
index 8769579..b3cb0f9 100644
--- a/src/displayapp/screens/WatchFaceDigital.cpp
+++ b/src/displayapp/screens/WatchFaceDigital.cpp
@@ -35,22 +35,22 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
settingsController.SetClockFace(0);
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_text(batteryIcon, Symbols::batteryFull);
+ lv_label_set_text_static(batteryIcon, Symbols::batteryFull);
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
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(0xFF0000));
- lv_label_set_text(batteryPlug, Symbols::plug);
+ lv_label_set_text_static(batteryPlug, Symbols::plug);
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
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(0x0000FF));
- lv_label_set_text(bleIcon, Symbols::bluetooth);
+ lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC));
+ lv_label_set_text_static(bleIcon, Symbols::bluetooth);
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
- lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
+ lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
label_date = lv_label_create(lv_scr_act(), nullptr);
@@ -71,26 +71,26 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
- lv_label_set_text(backgroundLabel, "");
+ lv_label_set_text_static(backgroundLabel, "");
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_text(heartbeatIcon, Symbols::heartBeat);
+ lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
- lv_label_set_text(heartbeatValue, "");
+ lv_label_set_text_static(heartbeatValue, "");
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
- lv_label_set_text(stepValue, "0");
+ lv_label_set_text_static(stepValue, "0");
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
stepIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
- lv_label_set_text(stepIcon, Symbols::shoe);
+ lv_label_set_text_static(stepIcon, Symbols::shoe);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
@@ -105,7 +105,7 @@ WatchFaceDigital::~WatchFaceDigital() {
void WatchFaceDigital::Refresh() {
powerPresent = batteryController.IsPowerPresent();
if (powerPresent.IsUpdated()) {
- lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
+ lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
}
batteryPercentRemaining = batteryController.PercentRemaining();
@@ -116,20 +116,20 @@ void WatchFaceDigital::Refresh() {
} 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));
+ lv_label_set_text_static(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
}
bleState = bleController.IsConnected();
if (bleState.IsUpdated()) {
- lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get()));
+ lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
}
- lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
- lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
- lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
+ lv_obj_realign(batteryIcon);
+ lv_obj_realign(batteryPlug);
+ lv_obj_realign(bleIcon);
notificationState = notificatioManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
- lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
+ lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
}
currentDateTime = dateTimeController.CurrentDateTime();
@@ -146,62 +146,41 @@ void WatchFaceDigital::Refresh() {
auto day = static_cast<unsigned>(yearMonthDay.day());
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
- int hour = time.hours().count();
- auto minute = time.minutes().count();
-
- char minutesChar[3];
- sprintf(minutesChar, "%02d", static_cast<int>(minute));
-
- char hoursChar[3];
- char ampmChar[3];
- if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
- sprintf(hoursChar, "%02d", hour);
- } else {
- if (hour == 0 && hour != 12) {
- hour = 12;
- sprintf(ampmChar, "AM");
- } else if (hour == 12 && hour != 0) {
- hour = 12;
- sprintf(ampmChar, "PM");
- } else if (hour < 12 && hour != 0) {
- sprintf(ampmChar, "AM");
- } else if (hour > 12 && hour != 0) {
- hour = hour - 12;
- sprintf(ampmChar, "PM");
- }
- sprintf(hoursChar, "%02d", hour);
- }
+ uint8_t hour = time.hours().count();
+ uint8_t minute = time.minutes().count();
- if ((hoursChar[0] != displayedChar[0]) or (hoursChar[1] != displayedChar[1]) or (minutesChar[0] != displayedChar[2]) or
- (minutesChar[1] != displayedChar[3])) {
- displayedChar[0] = hoursChar[0];
- displayedChar[1] = hoursChar[1];
- displayedChar[2] = minutesChar[0];
- displayedChar[3] = minutesChar[1];
+ if (displayedHour != hour || displayedMinute != minute) {
+ displayedHour = hour;
+ displayedMinute = minute;
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
- lv_label_set_text(label_time_ampm, ampmChar);
- if (hoursChar[0] == '0') {
- hoursChar[0] = ' ';
+ char ampmChar[3] = "AM";
+ if (hour == 0) {
+ hour = 12;
+ } else if (hour == 12) {
+ ampmChar[0] = 'P';
+ } else if (hour > 12) {
+ hour = hour - 12;
+ ampmChar[0] = 'P';
}
- }
-
- lv_label_set_text_fmt(label_time, "%s:%s", hoursChar, minutesChar);
-
- if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
+ lv_label_set_text(label_time_ampm, ampmChar);
+ lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
} else {
+ lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
}
}
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
- lv_label_set_text_fmt(label_date, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year);
+ lv_label_set_text_fmt(
+ label_date, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year);
} else {
- lv_label_set_text_fmt(label_date, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year);
+ lv_label_set_text_fmt(
+ label_date, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year);
}
- lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
+ lv_obj_realign(label_date);
currentYear = year;
currentMonth = month;
@@ -221,15 +200,15 @@ void WatchFaceDigital::Refresh() {
lv_label_set_text_static(heartbeatValue, "");
}
- lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
- lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
+ lv_obj_realign(heartbeatIcon);
+ lv_obj_realign(heartbeatValue);
}
stepCount = motionController.NbSteps();
motionSensorOk = motionController.IsSensorOk();
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
- lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
- lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
+ lv_obj_realign(stepValue);
+ lv_obj_realign(stepIcon);
}
}
diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h
index 627154c..ab3a028 100644
--- a/src/displayapp/screens/WatchFaceDigital.h
+++ b/src/displayapp/screens/WatchFaceDigital.h
@@ -35,7 +35,8 @@ namespace Pinetime {
void Refresh() override;
private:
- char displayedChar[5] {};
+ uint8_t displayedHour = -1;
+ uint8_t displayedMinute = -1;
uint16_t currentYear = 1970;
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
diff --git a/src/displayapp/screens/settings/SettingChimes.cpp b/src/displayapp/screens/settings/SettingChimes.cpp
new file mode 100644
index 0000000..543b5e0
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingChimes.cpp
@@ -0,0 +1,100 @@
+#include "displayapp/screens/settings/SettingChimes.h"
+#include <lvgl/lvgl.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Styles.h"
+#include "displayapp/screens/Screen.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ static void event_handler(lv_obj_t* obj, lv_event_t event) {
+ SettingChimes* screen = static_cast<SettingChimes*>(obj->user_data);
+ screen->UpdateSelected(obj, event);
+ }
+}
+
+SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
+ : Screen(app), settingsController {settingsController} {
+
+ lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
+
+ lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
+ lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
+ lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
+ lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
+
+ lv_obj_set_pos(container1, 10, 60);
+ lv_obj_set_width(container1, LV_HOR_RES - 20);
+ lv_obj_set_height(container1, LV_VER_RES - 50);
+ lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
+
+ lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_static(title, "Chimes");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 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);
+
+ optionsTotal = 0;
+ cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
+ lv_checkbox_set_text_static(cbOption[optionsTotal], " Off");
+ cbOption[optionsTotal]->user_data = this;
+ lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
+ SetRadioButtonStyle(cbOption[optionsTotal]);
+ if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::None) {
+ lv_checkbox_set_checked(cbOption[optionsTotal], true);
+ }
+
+ optionsTotal++;
+ cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
+ lv_checkbox_set_text_static(cbOption[optionsTotal], " Every hour");
+ cbOption[optionsTotal]->user_data = this;
+ lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
+ SetRadioButtonStyle(cbOption[optionsTotal]);
+ if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours) {
+ lv_checkbox_set_checked(cbOption[optionsTotal], true);
+ }
+
+ optionsTotal++;
+ cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
+ lv_checkbox_set_text_static(cbOption[optionsTotal], " Every 30 mins");
+ cbOption[optionsTotal]->user_data = this;
+ lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
+ SetRadioButtonStyle(cbOption[optionsTotal]);
+ if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours) {
+ lv_checkbox_set_checked(cbOption[optionsTotal], true);
+ }
+
+ optionsTotal++;
+}
+
+SettingChimes::~SettingChimes() {
+ lv_obj_clean(lv_scr_act());
+ settingsController.SaveSettings();
+}
+
+void SettingChimes::UpdateSelected(lv_obj_t* object, lv_event_t event) {
+ if (event == LV_EVENT_VALUE_CHANGED) {
+ for (uint8_t i = 0; i < optionsTotal; i++) {
+ if (object == cbOption[i]) {
+ lv_checkbox_set_checked(cbOption[i], true);
+ if (i == 0) {
+ settingsController.SetChimeOption(Controllers::Settings::ChimesOption::None);
+ }
+ if (i == 1) {
+ settingsController.SetChimeOption(Controllers::Settings::ChimesOption::Hours);
+ }
+ if (i == 2) {
+ settingsController.SetChimeOption(Controllers::Settings::ChimesOption::HalfHours);
+ }
+ } else {
+ lv_checkbox_set_checked(cbOption[i], false);
+ }
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingChimes.h b/src/displayapp/screens/settings/SettingChimes.h
new file mode 100644
index 0000000..653f87f
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingChimes.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/settings/Settings.h"
+#include "displayapp/screens/Screen.h"
+
+namespace Pinetime {
+
+ namespace Applications {
+ namespace Screens {
+
+ class SettingChimes : public Screen {
+ public:
+ SettingChimes(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
+ ~SettingChimes() override;
+
+ void UpdateSelected(lv_obj_t* object, lv_event_t event);
+
+ private:
+ Controllers::Settings& settingsController;
+ uint8_t optionsTotal;
+ lv_obj_t* cbOption[2];
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingPineTimeStyle.cpp b/src/displayapp/screens/settings/SettingPineTimeStyle.cpp
deleted file mode 100644
index f38ec3b..0000000
--- a/src/displayapp/screens/settings/SettingPineTimeStyle.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-#include "displayapp/screens/settings/SettingPineTimeStyle.h"
-#include <lvgl/lvgl.h>
-#include <displayapp/Colors.h>
-#include "displayapp/DisplayApp.h"
-#include "displayapp/screens/Symbols.h"
-
-using namespace Pinetime::Applications::Screens;
-
-namespace {
- static void event_handler(lv_obj_t* obj, lv_event_t event) {
- SettingPineTimeStyle* screen = static_cast<SettingPineTimeStyle*>(obj->user_data);
- screen->UpdateSelected(obj, event);
- }
-}
-
-SettingPineTimeStyle::SettingPineTimeStyle(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
- : Screen(app), settingsController {settingsController} {
- timebar = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBG()));
- lv_obj_set_style_local_radius(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(timebar, 200, 240);
- lv_obj_align(timebar, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 0);
-
- // Display the time
-
- timeDD1 = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
- lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
- lv_label_set_text(timeDD1, "12");
- lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5);
-
- timeDD2 = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light);
- lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
- lv_label_set_text(timeDD2, "34");
- lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5);
-
- timeAMPM = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
- lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3);
- lv_label_set_text(timeAMPM, "A\nM");
- lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20);
-
- // Create a 40px wide bar down the right side of the screen
-
- sidebar = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBar()));
- lv_obj_set_style_local_radius(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(sidebar, 40, 240);
- lv_obj_align(sidebar, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
-
- // Display icons
-
- batteryIcon = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(batteryIcon, Symbols::batteryFull);
- lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
-
- bleIcon = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(bleIcon, Symbols::bluetooth);
- lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25);
-
- // Calendar icon
-
- calendarOuter = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(calendarOuter, 34, 34);
- lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
-
- calendarInner = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
- lv_obj_set_style_local_radius(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(calendarInner, 27, 27);
- lv_obj_align(calendarInner, calendarOuter, LV_ALIGN_CENTER, 0, 0);
-
- calendarBar1 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_radius(calendarBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(calendarBar1, 3, 12);
- lv_obj_align(calendarBar1, calendarOuter, LV_ALIGN_IN_TOP_MID, -6, -3);
-
- calendarBar2 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_radius(calendarBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(calendarBar2, 3, 12);
- lv_obj_align(calendarBar2, calendarOuter, LV_ALIGN_IN_TOP_MID, 6, -3);
-
- calendarCrossBar1 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_radius(calendarCrossBar1, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(calendarCrossBar1, 8, 3);
- lv_obj_align(calendarCrossBar1, calendarBar1, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
-
- calendarCrossBar2 = lv_obj_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_bg_color(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_obj_set_style_local_radius(calendarCrossBar2, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
- lv_obj_set_size(calendarCrossBar2, 8, 3);
- lv_obj_align(calendarCrossBar2, calendarBar2, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
-
- // Display date
-
- dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(dateDayOfWeek, "THU");
- lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34);
-
- dateDay = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(dateDay, "25");
- lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3);
-
- dateMonth = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
- lv_label_set_text(dateMonth, "MAR");
- lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32);
-
- // Step count gauge
- needle_colors[0] = LV_COLOR_WHITE;
- stepGauge = lv_gauge_create(lv_scr_act(), nullptr);
- lv_gauge_set_needle_count(stepGauge, 1, needle_colors);
- lv_obj_set_size(stepGauge, 40, 40);
- lv_obj_align(stepGauge, sidebar, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
- lv_gauge_set_scale(stepGauge, 360, 11, 0);
- lv_gauge_set_angle_offset(stepGauge, 180);
- lv_gauge_set_critical_value(stepGauge, (100));
- lv_gauge_set_range(stepGauge, 0, (100));
- lv_gauge_set_value(stepGauge, 0, 0);
-
- lv_obj_set_style_local_pad_right(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
- lv_obj_set_style_local_pad_left(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
- lv_obj_set_style_local_pad_bottom(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 3);
- lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
- lv_obj_set_style_local_scale_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4);
- lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, 4);
- lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
- lv_obj_set_style_local_line_opa(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, LV_OPA_COVER);
- lv_obj_set_style_local_line_width(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 3);
- lv_obj_set_style_local_pad_inner(stepGauge, LV_GAUGE_PART_NEEDLE, LV_STATE_DEFAULT, 4);
-
- backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_click(backgroundLabel, true);
- lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
- lv_obj_set_size(backgroundLabel, 240, 240);
- lv_obj_set_pos(backgroundLabel, 0, 0);
- lv_label_set_text(backgroundLabel, "");
-
- btnNextTime = lv_btn_create(lv_scr_act(), nullptr);
- btnNextTime->user_data = this;
- lv_obj_set_size(btnNextTime, 60, 60);
- lv_obj_align(btnNextTime, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, -80);
- lv_obj_set_style_local_bg_opa(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnNextTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
- lv_obj_set_event_cb(btnNextTime, event_handler);
-
- btnPrevTime = lv_btn_create(lv_scr_act(), nullptr);
- btnPrevTime->user_data = this;
- lv_obj_set_size(btnPrevTime, 60, 60);
- lv_obj_align(btnPrevTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, -80);
- lv_obj_set_style_local_bg_opa(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnPrevTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
- lv_obj_set_event_cb(btnPrevTime, event_handler);
-
- btnNextBar = lv_btn_create(lv_scr_act(), nullptr);
- btnNextBar->user_data = this;
- lv_obj_set_size(btnNextBar, 60, 60);
- lv_obj_align(btnNextBar, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0);
- lv_obj_set_style_local_bg_opa(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnNextBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
- lv_obj_set_event_cb(btnNextBar, event_handler);
-
- btnPrevBar = lv_btn_create(lv_scr_act(), nullptr);
- btnPrevBar->user_data = this;
- lv_obj_set_size(btnPrevBar, 60, 60);
- lv_obj_align(btnPrevBar, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0);
- lv_obj_set_style_local_bg_opa(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnPrevBar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
- lv_obj_set_event_cb(btnPrevBar, event_handler);
-
- btnNextBG = lv_btn_create(lv_scr_act(), nullptr);
- btnNextBG->user_data = this;
- lv_obj_set_size(btnNextBG, 60, 60);
- lv_obj_align(btnNextBG, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 80);
- lv_obj_set_style_local_bg_opa(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnNextBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, ">");
- lv_obj_set_event_cb(btnNextBG, event_handler);
-
- btnPrevBG = lv_btn_create(lv_scr_act(), nullptr);
- btnPrevBG->user_data = this;
- lv_obj_set_size(btnPrevBG, 60, 60);
- lv_obj_align(btnPrevBG, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 80);
- lv_obj_set_style_local_bg_opa(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnPrevBG, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "<");
- lv_obj_set_event_cb(btnPrevBG, event_handler);
-
- btnReset = lv_btn_create(lv_scr_act(), nullptr);
- btnReset->user_data = this;
- lv_obj_set_size(btnReset, 60, 60);
- lv_obj_align(btnReset, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
- lv_obj_set_style_local_bg_opa(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnReset, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rst");
- lv_obj_set_event_cb(btnReset, event_handler);
-
- btnRandom = lv_btn_create(lv_scr_act(), nullptr);
- btnRandom->user_data = this;
- lv_obj_set_size(btnRandom, 60, 60);
- lv_obj_align(btnRandom, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
- lv_obj_set_style_local_bg_opa(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_30);
- lv_obj_set_style_local_value_str(btnRandom, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Rnd");
- lv_obj_set_event_cb(btnRandom, event_handler);
-}
-
-SettingPineTimeStyle::~SettingPineTimeStyle() {
- lv_obj_clean(lv_scr_act());
- settingsController.SaveSettings();
-}
-
-void SettingPineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event) {
- auto valueTime = settingsController.GetPTSColorTime();
- auto valueBar = settingsController.GetPTSColorBar();
- auto valueBG = settingsController.GetPTSColorBG();
-
- if (event == LV_EVENT_CLICKED) {
- if (object == btnNextTime) {
- valueTime = GetNext(valueTime);
-
- settingsController.SetPTSColorTime(valueTime);
- lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
- lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
- lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
- }
- if (object == btnPrevTime) {
- valueTime = GetPrevious(valueTime);
- settingsController.SetPTSColorTime(valueTime);
- lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
- lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
- lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(valueTime));
- }
- if (object == btnNextBar) {
- valueBar = GetNext(valueBar);
- if(valueBar == Controllers::Settings::Colors::Black)
- valueBar = GetNext(valueBar);
- settingsController.SetPTSColorBar(valueBar);
- lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
- }
- if (object == btnPrevBar) {
- valueBar = GetPrevious(valueBar);
- if(valueBar == Controllers::Settings::Colors::Black)
- valueBar = GetPrevious(valueBar);
- settingsController.SetPTSColorBar(valueBar);
- lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBar));
- }
- if (object == btnNextBG) {
- valueBG = GetNext(valueBG);
- settingsController.SetPTSColorBG(valueBG);
- lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
- }
- if (object == btnPrevBG) {
- valueBG = GetPrevious(valueBG);
- settingsController.SetPTSColorBG(valueBG);
- lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(valueBG));
- }
- if (object == btnReset) {
- settingsController.SetPTSColorTime(Controllers::Settings::Colors::Teal);
- lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
- lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
- lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
- settingsController.SetPTSColorBar(Controllers::Settings::Colors::Teal);
- lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Teal));
- settingsController.SetPTSColorBG(Controllers::Settings::Colors::Black);
- lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(Controllers::Settings::Colors::Black));
- }
- if (object == btnRandom) {
- uint8_t randTime = rand() % 17;
- uint8_t randBar = rand() % 17;
- uint8_t randBG = rand() % 17;
- // Check if the time color is the same as its background, or if the sidebar is black. If so, change them to more useful values.
- if (randTime == randBG) {
- randBG += 1;
- }
- if (randBar == 3) {
- randBar -= 1;
- }
- settingsController.SetPTSColorTime(static_cast<Controllers::Settings::Colors>(randTime));
- lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime)));
- lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime)));
- lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randTime)));
- settingsController.SetPTSColorBar(static_cast<Controllers::Settings::Colors>(randBar));
- lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randBar)));
- settingsController.SetPTSColorBG(static_cast<Controllers::Settings::Colors>(randBG));
- lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(static_cast<Controllers::Settings::Colors>(randBG)));
- }
- }
-}
-
-Pinetime::Controllers::Settings::Colors SettingPineTimeStyle::GetNext(Pinetime::Controllers::Settings::Colors color) {
- auto colorAsInt = static_cast<uint8_t>(color);
- Pinetime::Controllers::Settings::Colors nextColor;
- if (colorAsInt < 16) {
- nextColor = static_cast<Controllers::Settings::Colors>(colorAsInt + 1);
- } else {
- nextColor = static_cast<Controllers::Settings::Colors>(0);
- }
- return nextColor;
-}
-
-Pinetime::Controllers::Settings::Colors SettingPineTimeStyle::GetPrevious(Pinetime::Controllers::Settings::Colors color) {
- auto colorAsInt = static_cast<uint8_t>(color);
- Pinetime::Controllers::Settings::Colors prevColor;
-
- if (colorAsInt > 0) {
- prevColor = static_cast<Controllers::Settings::Colors>(colorAsInt - 1);
- } else {
- prevColor = static_cast<Controllers::Settings::Colors>(16);
- }
- return prevColor;
-}
diff --git a/src/displayapp/screens/settings/SettingPineTimeStyle.h b/src/displayapp/screens/settings/SettingPineTimeStyle.h
deleted file mode 100644
index 397bd86..0000000
--- a/src/displayapp/screens/settings/SettingPineTimeStyle.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#pragma once
-
-#include <cstdint>
-#include <lvgl/lvgl.h>
-#include "components/settings/Settings.h"
-#include "displayapp/screens/Screen.h"
-
-namespace Pinetime {
-
- namespace Applications {
- namespace Screens {
-
- class SettingPineTimeStyle : public Screen{
- public:
- SettingPineTimeStyle(DisplayApp* app, Pinetime::Controllers::Settings &settingsController);
- ~SettingPineTimeStyle() override;
-
- void UpdateSelected(lv_obj_t *object, lv_event_t event);
-
- private:
- Controllers::Settings& settingsController;
-
- Pinetime::Controllers::Settings::Colors GetNext(Controllers::Settings::Colors color);
- Pinetime::Controllers::Settings::Colors GetPrevious(Controllers::Settings::Colors color);
-
- lv_obj_t * btnNextTime;
- lv_obj_t * btnPrevTime;
- lv_obj_t * btnNextBar;
- lv_obj_t * btnPrevBar;
- lv_obj_t * btnNextBG;
- lv_obj_t * btnPrevBG;
- lv_obj_t * btnReset;
- lv_obj_t * btnRandom;
- lv_obj_t * timebar;
- lv_obj_t * sidebar;
- lv_obj_t * timeDD1;
- lv_obj_t * timeDD2;
- lv_obj_t * timeAMPM;
- lv_obj_t * dateDayOfWeek;
- lv_obj_t * dateDay;
- lv_obj_t * dateMonth;
- lv_obj_t * backgroundLabel;
- lv_obj_t * batteryIcon;
- lv_obj_t * bleIcon;
- lv_obj_t * calendarOuter;
- lv_obj_t * calendarInner;
- lv_obj_t * calendarBar1;
- lv_obj_t * calendarBar2;
- lv_obj_t * calendarCrossBar1;
- lv_obj_t * calendarCrossBar2;
- lv_obj_t * stepGauge;
- lv_color_t needle_colors[1];
- };
- }
- }
-}
diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.cpp b/src/displayapp/screens/settings/SettingShakeThreshold.cpp
new file mode 100644
index 0000000..1791b55
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingShakeThreshold.cpp
@@ -0,0 +1,137 @@
+#include "SettingShakeThreshold.h"
+#include <lvgl/lvgl.h>
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Screen.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ void event_handler(lv_obj_t* obj, lv_event_t event) {
+ SettingShakeThreshold* screen = static_cast<SettingShakeThreshold*>(obj->user_data);
+ screen->UpdateSelected(obj, event);
+ }
+}
+
+SettingShakeThreshold::SettingShakeThreshold(DisplayApp* app,
+ Controllers::Settings& settingsController,
+ Controllers::MotionController& motionController,
+ System::SystemTask& systemTask)
+ : Screen(app), settingsController {settingsController}, motionController {motionController}, systemTask {systemTask} {
+
+ lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_text_static(title, "Wake Sensitivity");
+ lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
+ lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0);
+
+ positionArc = lv_arc_create(lv_scr_act(), nullptr);
+ positionArc->user_data = this;
+
+ lv_obj_set_event_cb(positionArc, event_handler);
+ lv_arc_set_bg_angles(positionArc, 180, 360);
+ lv_arc_set_range(positionArc, 0, 4095);
+ lv_arc_set_adjustable(positionArc, true);
+ lv_obj_set_width(positionArc, lv_obj_get_width(lv_scr_act()) - 10);
+ lv_obj_set_height(positionArc, 240);
+ lv_obj_align(positionArc, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
+
+ animArc = lv_arc_create(positionArc, positionArc);
+ lv_arc_set_adjustable(animArc, false);
+ lv_obj_set_width(animArc, lv_obj_get_width(positionArc));
+ lv_obj_set_height(animArc, lv_obj_get_height(positionArc));
+ lv_obj_align_mid(animArc, positionArc, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_line_opa(animArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
+ lv_obj_set_style_local_line_opa(animArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_OPA_70);
+ lv_obj_set_style_local_line_opa(animArc, LV_ARC_PART_KNOB, LV_STATE_DEFAULT, LV_OPA_0);
+ lv_obj_set_style_local_line_color(animArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
+ lv_obj_set_style_local_bg_color(animArc, LV_ARC_PART_BG, LV_STATE_CHECKED, LV_COLOR_TRANSP);
+
+ animArc->user_data = this;
+ lv_obj_set_click(animArc, false);
+
+ calButton = lv_btn_create(lv_scr_act(), nullptr);
+ calButton->user_data = this;
+ lv_obj_set_event_cb(calButton, event_handler);
+ lv_obj_set_height(calButton, 80);
+ lv_obj_set_width(calButton, 200);
+ lv_obj_align(calButton, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ lv_btn_set_checkable(calButton, true);
+ calLabel = lv_label_create(calButton, NULL);
+ lv_label_set_text(calLabel, "Calibrate");
+
+ lv_arc_set_value(positionArc, settingsController.GetShakeThreshold());
+
+ vDecay = xTaskGetTickCount();
+ calibrating = false;
+ EnableForCal = false;
+ if(!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake)){
+ EnableForCal = true;
+ settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::Shake,true);
+ }
+ refreshTask = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
+}
+
+SettingShakeThreshold::~SettingShakeThreshold() {
+ settingsController.SetShakeThreshold(lv_arc_get_value(positionArc));
+
+ if(EnableForCal){
+ settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::Shake,false);
+ EnableForCal = false;
+ }
+ lv_task_del(refreshTask);
+ settingsController.SaveSettings();
+ lv_obj_clean(lv_scr_act());
+}
+
+void SettingShakeThreshold::Refresh() {
+
+ if (calibrating == 1) {
+ if (xTaskGetTickCount() - vCalTime > pdMS_TO_TICKS(2000)) {
+ vCalTime = xTaskGetTickCount();
+ calibrating = 2;
+ lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_RED);
+ lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_RED);
+ lv_label_set_text(calLabel, "Shake!!");
+ }
+ }
+ if (calibrating == 2) {
+
+ if ((motionController.currentShakeSpeed() - 300) > lv_arc_get_value(positionArc)) {
+ lv_arc_set_value(positionArc, (int16_t) motionController.currentShakeSpeed() - 300);
+ }
+ if (xTaskGetTickCount() - vCalTime > pdMS_TO_TICKS(7500)) {
+ lv_btn_set_state(calButton, LV_STATE_DEFAULT);
+ lv_event_send(calButton, LV_EVENT_VALUE_CHANGED, NULL);
+ }
+ }
+ if (motionController.currentShakeSpeed() - 300 > lv_arc_get_value(animArc)) {
+ lv_arc_set_value(animArc, (uint16_t) motionController.currentShakeSpeed() - 300);
+ vDecay = xTaskGetTickCount();
+ } else if ((xTaskGetTickCount() - vDecay) > pdMS_TO_TICKS(1500)) {
+ lv_arc_set_value(animArc, lv_arc_get_value(animArc) - 25);
+ }
+}
+
+void SettingShakeThreshold::UpdateSelected(lv_obj_t* object, lv_event_t event) {
+
+ switch (event) {
+ case LV_EVENT_VALUE_CHANGED: {
+ if (object == calButton) {
+ if (lv_btn_get_state(calButton) == LV_BTN_STATE_CHECKED_RELEASED && calibrating == 0) {
+ lv_arc_set_value(positionArc, 0);
+ calibrating = 1;
+ vCalTime = xTaskGetTickCount();
+ lv_label_set_text(calLabel, "Ready!");
+ lv_obj_set_click(positionArc, false);
+ lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_GREEN);
+ lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_GREEN);
+ } else if (lv_btn_get_state(calButton) == LV_BTN_STATE_RELEASED) {
+ calibrating = 0;
+ lv_obj_set_click(positionArc, true);
+ lv_label_set_text(calLabel, "Calibrate");
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.h b/src/displayapp/screens/settings/SettingShakeThreshold.h
new file mode 100644
index 0000000..b9ddd8b
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingShakeThreshold.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "components/settings/Settings.h"
+#include "displayapp/screens/Screen.h"
+#include <components/motion/MotionController.h>
+namespace Pinetime {
+
+ namespace Applications {
+ namespace Screens {
+
+ class SettingShakeThreshold : public Screen {
+ public:
+ SettingShakeThreshold(DisplayApp* app,
+ Pinetime::Controllers::Settings& settingsController,
+ Controllers::MotionController& motionController,
+ System::SystemTask& systemTask);
+
+ ~SettingShakeThreshold() override;
+ void Refresh() override;
+ void UpdateSelected(lv_obj_t* object, lv_event_t event);
+
+ private:
+ Controllers::Settings& settingsController;
+ Controllers::MotionController& motionController;
+ System::SystemTask& systemTask;
+ uint8_t calibrating;
+ bool EnableForCal;
+ uint32_t vDecay,vCalTime;
+ lv_obj_t *positionArc, *animArc,*calButton, *calLabel;
+ lv_task_t* refreshTask;
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp
index 8339d9a..e1b6e36 100644
--- a/src/displayapp/screens/settings/SettingWakeUp.cpp
+++ b/src/displayapp/screens/settings/SettingWakeUp.cpp
@@ -65,6 +65,14 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_checkbox_set_checked(cbOption[optionsTotal], true);
}
optionsTotal++;
+ cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
+ lv_checkbox_set_text_static(cbOption[optionsTotal], " Shake Wake");
+ cbOption[optionsTotal]->user_data = this;
+ lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
+ if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake)) {
+ lv_checkbox_set_checked(cbOption[optionsTotal], true);
+ }
+ optionsTotal++;
}
SettingWakeUp::~SettingWakeUp() {
diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h
index b9a31dc..cd244ae 100644
--- a/src/displayapp/screens/settings/SettingWakeUp.h
+++ b/src/displayapp/screens/settings/SettingWakeUp.h
@@ -20,7 +20,7 @@ namespace Pinetime {
private:
Controllers::Settings& settingsController;
uint8_t optionsTotal;
- lv_obj_t* cbOption[4];
+ lv_obj_t* cbOption[5];
// When UpdateSelected is called, it uses lv_checkbox_set_checked,
// which can cause extra events to be fired,
// which might trigger UpdateSelected again, causing a loop.
diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp
index 392c12e..7bc90b4 100644
--- a/src/displayapp/screens/settings/Settings.cpp
+++ b/src/displayapp/screens/settings/Settings.cpp
@@ -47,12 +47,10 @@ std::unique_ptr<Screen> Settings::CreateScreen1() {
std::unique_ptr<Screen> Settings::CreateScreen2() {
- std::array<Screens::List::Applications, 4> applications {{
- {Symbols::shoe, "Steps", Apps::SettingSteps},
- {Symbols::clock, "Set date", Apps::SettingSetDate},
- {Symbols::clock, "Set time", Apps::SettingSetTime},
- {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}
- }};
+ std::array<Screens::List::Applications, 4> applications {{{Symbols::shoe, "Steps", Apps::SettingSteps},
+ {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 +58,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::clock, "Chimes", Apps::SettingChimes},
+ {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
{Symbols::check, "Firmware", Apps::FirmwareValidation},
- {Symbols::list, "About", Apps::SysInfo},
- {Symbols::none, "None", Apps::None},
+ {Symbols::list, "About", Apps::SysInfo}
}};
return std::make_unique<Screens::List>(2, 3, app, settingsController, applications);
diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h
index cc30fdc..4d5ab4c 100644
--- a/src/systemtask/Messages.h
+++ b/src/systemtask/Messages.h
@@ -21,6 +21,8 @@ namespace Pinetime {
EnableSleeping,
DisableSleeping,
OnNewDay,
+ OnNewHour,
+ OnNewHalfHour,
OnChargingEvent,
OnPairing,
SetOffAlarm,
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index a95d479..fc3e840 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -239,6 +239,7 @@ void SystemTask::Work() {
if (!bleController.IsFirmwareUpdating()) {
doNotGoToSleep = false;
}
+ ReloadIdleTimer();
break;
case Messages::DisableSleeping:
doNotGoToSleep = true;
@@ -343,18 +344,18 @@ void SystemTask::Work() {
xTimerStart(dimTimer, 0);
break;
case Messages::StartFileTransfer:
- NRF_LOG_INFO("[systemtask] FS Started");
+ NRF_LOG_INFO("[systemtask] FS Started");
doNotGoToSleep = true;
if (isSleeping && !isWakingUp)
GoToRunning();
- //TODO add intent of fs access icon or something
+ // TODO add intent of fs access icon or something
break;
case Messages::StopFileTransfer:
NRF_LOG_INFO("[systemtask] FS Stopped");
doNotGoToSleep = false;
xTimerStart(dimTimer, 0);
- //TODO add intent of fs access icon or something
- break;
+ // TODO add intent of fs access icon or something
+ break;
case Messages::OnTouchEvent:
if (touchHandler.GetNewTouchInfo()) {
touchHandler.UpdateLvglTouchPoint();
@@ -403,6 +404,26 @@ void SystemTask::Work() {
// Remember we'll have to reset the counter next time we're awake
stepCounterMustBeReset = true;
break;
+ case Messages::OnNewHour:
+ using Pinetime::Controllers::AlarmController;
+ if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && alarmController.State() != AlarmController::AlarmState::Alerting) {
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ displayApp.PushMessage(Pinetime::Applications::Display::Messages::Clock);
+ }
+ motorController.RunForDuration(35);
+ }
+ break;
+ case Messages::OnNewHalfHour:
+ using Pinetime::Controllers::AlarmController;
+ if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && alarmController.State() != AlarmController::AlarmState::Alerting) {
+ if (isSleeping && !isWakingUp) {
+ GoToRunning();
+ displayApp.PushMessage(Pinetime::Applications::Display::Messages::Clock);
+ }
+ motorController.RunForDuration(35);
+ }
+ break;
case Messages::OnChargingEvent:
batteryController.ReadPowerState();
motorController.RunForDuration(15);
@@ -457,10 +478,10 @@ void SystemTask::UpdateMotion() {
return;
}
- if (isSleeping && !settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) {
+ if (isSleeping && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) ||
+ settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake))) {
return;
}
-
if (stepCounterMustBeReset) {
motionSensor.ResetStepCounter();
stepCounterMustBeReset = false;
@@ -470,7 +491,13 @@ void SystemTask::UpdateMotion() {
motionController.IsSensorOk(motionSensor.IsOk());
motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps);
- if (motionController.ShouldWakeUp(isSleeping)) {
+
+ if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) &&
+ motionController.Should_RaiseWake(isSleeping)) {
+ GoToRunning();
+ }
+ if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) &&
+ motionController.Should_ShakeWake(settingsController.GetShakeThreshold())) {
GoToRunning();
}
}
diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h
index e2e6de7..abeffd2 100644
--- a/src/systemtask/SystemTask.h
+++ b/src/systemtask/SystemTask.h
@@ -3,6 +3,7 @@
#include <memory>
#include <FreeRTOS.h>
+#include <queue.h>
#include <task.h>
#include <timers.h>
#include <heartratetask/HeartRateTask.h>