diff options
| -rw-r--r-- | CMakeLists.txt | 12 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rwxr-xr-x | cmake-nRF5x/CMake_nRF5x.cmake | 7 | ||||
| -rw-r--r-- | doc/buildAndProgram.md | 15 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 26 | ||||
| -rw-r--r-- | src/displayapp/Apps.h | 2 | ||||
| -rw-r--r-- | src/displayapp/DisplayApp.cpp | 40 | ||||
| -rw-r--r-- | src/displayapp/DisplayAppRecovery.cpp | 6 | ||||
| -rw-r--r-- | src/displayapp/fonts/Readme.md | 2 | ||||
| -rw-r--r-- | src/displayapp/fonts/jetbrains_mono_bold_20.c | 105 | ||||
| -rw-r--r-- | src/displayapp/screens/ApplicationList.cpp | 14 | ||||
| -rw-r--r-- | src/displayapp/screens/Clock.cpp | 8 | ||||
| -rw-r--r-- | src/displayapp/screens/Notifications.cpp | 16 | ||||
| -rw-r--r-- | src/displayapp/screens/StopWatch.cpp | 210 | ||||
| -rw-r--r-- | src/displayapp/screens/StopWatch.h | 86 | ||||
| -rw-r--r-- | src/displayapp/screens/Symbols.h | 3 | ||||
| -rw-r--r-- | src/displayapp/screens/SystemInfo.cpp | 6 | ||||
| -rw-r--r-- | src/displayapp/screens/WatchFaceAnalog.cpp | 2 | ||||
| m--------- | src/libs/lvgl | 0 | ||||
| -rw-r--r-- | src/main.cpp | 6 | ||||
| -rw-r--r-- | src/recoveryLoader.cpp | 6 | ||||
| -rw-r--r-- | src/systemtask/SystemTask.cpp | 8 |
22 files changed, 456 insertions, 128 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 54ef9faf..f2edbc4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,15 @@ cmake_minimum_required(VERSION 3.10) -project(pinetime VERSION 0.14.1 LANGUAGES C CXX ASM) +project(pinetime VERSION 0.15.0 LANGUAGES C CXX ASM) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 14) + +# set(CMAKE_GENERATOR "Unix Makefiles") +set(CMAKE_C_EXTENSIONS OFF) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(NRF_TARGET "nrf52") @@ -44,9 +44,11 @@ As of now, here is the list of achievements of this project: * Notification (displays the last notification received) * Paddle (single player pong-like game) * Two (2048 clone game) - - Supported by 2 companion apps (development is in progress): + * Stopwatch (with all the necessary functions such as play, pause, lap, stop) + - Supported by 3 companion apps (development is in progress): * [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android) * [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux) + * [Siglo](https://github.com/alexr4535/siglo) (on Linux) * **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY) - **[Experimental]** OTA (Over-the-air) update via BLE - **[Experimental]** Bootloader based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/) diff --git a/cmake-nRF5x/CMake_nRF5x.cmake b/cmake-nRF5x/CMake_nRF5x.cmake index c1785d36..ead7b9f6 100755 --- a/cmake-nRF5x/CMake_nRF5x.cmake +++ b/cmake-nRF5x/CMake_nRF5x.cmake @@ -36,9 +36,6 @@ macro(nRF5x_setup) set(CMAKE_OSX_SYSROOT "/") set(CMAKE_OSX_DEPLOYMENT_TARGET "") - # language standard/version settings - set(CMAKE_C_STANDARD 99) - set(CMAKE_CXX_STANDARD 11) # CPU specyfic settings if (NRF_TARGET MATCHES "nrf51") @@ -86,8 +83,8 @@ macro(nRF5x_setup) set(CMAKE_CXX_FLAGS "${COMMON_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g3") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") - set(CMAKE_ASM_FLAGS "-MP -MD -std=c99 -x assembler-with-cpp") - set(CMAKE_EXE_LINKER_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} ${CPU_FLAGS} -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm") + set(CMAKE_ASM_FLAGS "-MP -MD -x assembler-with-cpp") + set(CMAKE_EXE_LINKER_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} ${CPU_FLAGS} -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm") # note: we must override the default cmake linker flags so that CMAKE_C_FLAGS are not added implicitly set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_COMPILER} <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_C_COMPILER} <LINK_FLAGS> <OBJECTS> -lstdc++ -o <TARGET> <LINK_LIBRARIES>") diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md index 484916a8..cf349094 100644 --- a/doc/buildAndProgram.md +++ b/doc/buildAndProgram.md @@ -22,18 +22,23 @@ CMake configures the project according to variables you specify the command line **ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2020-q2-update/`| **NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`| **USE_JLINK, USE_GDB_CLIENT and USE_OPENOCD**|Enable *JLink* mode, *GDB Client* (Black Magic Probe) mode or *OpenOCD* mode (set the one you want to use to `1`)|`-DUSE_JLINK=1` -**CMAKE_BUILD_TYPE**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug` +**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug` **NRFJPROG**|Path to the NRFJProg executable. Used only if `USE_JLINK` is 1.|`-DNRFJPROG=/opt/nrfjprog/nrfjprog` **GDB_CLIENT_BIN_PATH**|Path to arm-none-eabi-gdb executable. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_BIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb` **GDB_CLIENT_TARGET_REMOTE**|Target remote connection string. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_TARGET_REMOTE=/dev/ttyACM0` -**BUILD_DFU (\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-BUILD_DFU=1` +**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-BUILD_DFU=1` -####(*) Note about **BUILD_DFU**: +####(**) Note about **CMAKE_BUILD_TYPE**: +By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/JF002/InfiniTime/releases) new versions of InfiniTime. + +The *Debug* mode disables all optimizations, which makes the code easier to debug. However, the binary size will likely be too big to fit in the internal flash memory. If you want to build and debug a *Debug* binary, you'll need to disable some parts of the code. For example, the icons for the **Navigation** app use a lot of memory space. You can comment the content of `m_iconMap` in the [Navigation](https://github.com/JF002/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory. + +####(**) Note about **BUILD_DFU**: DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mecanism. To generate the DFU file, the Python tool [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) is needed on your system. Check that this tool is properly installed before enabling this option. #### CMake command line for JLink ``` -cmake -DCMAKE_BUILD_TYPE=Debug -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_JLINK=1 -DNRFJPROG=... ../ +cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_JLINK=1 -DNRFJPROG=... ../ ``` #### CMake command line for GDB Client (Black Magic Probe) @@ -57,7 +62,7 @@ During the project generation, CMake created the following targets: - **pinetime-mcuboot-recovery** : build pinetime-recovery with bootloader support - **pinetime-mcuboot-recovery-loader** : build pinetime-recovery-loader with bootloader support -If you just want to build the project and run it on the Pinetime, using *pinetime-app* is recommanded. See [this page](../bootloader/README.md) for more info about bootloader support. +If you just want to build the project and run it on the Pinetime, using *pinetime-app* is recommended. See [this page](../bootloader/README.md) for more info about bootloader support. Build: ``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac533540..1183bb3b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,16 +3,6 @@ cmake_minimum_required(VERSION 3.10) project(pinetime-app C CXX ASM) -set(CMAKE_C_STANDARD 99) -set(CMAKE_CXX_STANDARD 14) - -# set(CMAKE_GENERATOR "Unix Makefiles") -set(CMAKE_C_EXTENSIONS OFF) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - # define some variables just for this example to determine file locations set(NRF_PROJECT_NAME pinetime-app) set(NRF_BOARD pca10040) @@ -485,6 +475,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Meter.cpp displayapp/screens/InfiniPaint.cpp displayapp/screens/Paddle.cpp + displayapp/screens/StopWatch.cpp displayapp/screens/BatteryIcon.cpp displayapp/screens/BleIcon.cpp displayapp/screens/NotificationIcon.cpp @@ -644,6 +635,7 @@ set(INCLUDE_FILES displayapp/screens/Tile.h displayapp/screens/Meter.h displayapp/screens/InfiniPaint.h + displayapp/screens/StopWatch.h displayapp/screens/Paddle.h displayapp/screens/DropDownDemo.h displayapp/screens/BatteryIcon.h @@ -873,8 +865,6 @@ target_compile_options(${EXECUTABLE_NAME} PUBLIC set_target_properties(${EXECUTABLE_NAME} PROPERTIES SUFFIX ".out" LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_FILE_NAME}.map" - CXX_STANDARD 11 - C_STANDARD 99 ) add_custom_command(TARGET ${EXECUTABLE_NAME} @@ -905,8 +895,6 @@ target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES SUFFIX ".out" LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map" - CXX_STANDARD 11 - C_STANDARD 99 ) add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME} @@ -944,8 +932,6 @@ target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES SUFFIX ".out" LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map" - CXX_STANDARD 11 - C_STANDARD 99 ) add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME} @@ -975,9 +961,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.map" - CXX_STANDARD 11 - C_STANDARD 99 + LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME} @@ -1019,8 +1003,6 @@ add_dependencies(${EXECUTABLE_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY_MCUBOOT set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES SUFFIX ".out" LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map" - CXX_STANDARD 11 - C_STANDARD 99 ) add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME} @@ -1054,8 +1036,6 @@ add_dependencies(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES SUFFIX ".out" LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map" - CXX_STANDARD 11 - C_STANDARD 99 ) add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index 028fc80c..74b121df 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -2,6 +2,6 @@ namespace Pinetime { namespace Applications { - enum class Apps {None, Launcher, Clock, SysInfo, Meter, Brightness, Music, FirmwareValidation, Paint, Paddle, Notifications, Twos, HeartRate, Navigation}; + enum class Apps {None, Launcher, Clock, SysInfo, Meter, Brightness, Music, FirmwareValidation, Paint, Paddle, Notifications, Twos, HeartRate, Navigation, StopWatch}; } } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index fee973ac..3de26991 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -12,6 +12,7 @@ #include "displayapp/screens/FirmwareValidation.h" #include "displayapp/screens/InfiniPaint.h" #include "displayapp/screens/Paddle.h" +#include "displayapp/screens/StopWatch.h" #include "displayapp/screens/Meter.h" #include "displayapp/screens/Music.h" #include "displayapp/screens/Navigation.h" @@ -122,7 +123,7 @@ void DisplayApp::Refresh() { currentScreen.reset(nullptr); lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Up); onClockApp = false; - currentScreen.reset(new Screens::Notifications(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview)); + currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Preview); } } break; @@ -160,10 +161,10 @@ void DisplayApp::Refresh() { // lvgl.SetFullRefresh(components::LittleVgl::FullRefreshDirections::Down); // currentScreen.reset(nullptr); // if(toggle) { -// currentScreen.reset(new Screens::Tile(this)); +// currentScreen = std::make_unique<Screens::Tile>(this); // toggle = false; // } else { -// currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); +// currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController); // toggle = true; // } @@ -171,10 +172,14 @@ void DisplayApp::Refresh() { case Messages::BleFirmwareUpdateStarted: lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); currentScreen.reset(nullptr); - currentScreen.reset(new Screens::FirmwareUpdate(this, bleController)); + currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController); onClockApp = false; break; + case Messages::UpdateDateTime: + // Added to remove warning + // What should happen here? + break; } } @@ -197,22 +202,23 @@ void DisplayApp::RunningState() { onClockApp = false; switch(nextApp) { case Apps::None: - case Apps::Launcher: currentScreen.reset(new Screens::ApplicationList(this, settingsController)); break; + case Apps::Launcher: currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController); break; case Apps::Clock: - currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController)); + currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController); onClockApp = true; break; - case Apps::SysInfo: currentScreen.reset(new Screens::SystemInfo(this, dateTimeController, batteryController, brightnessController, bleController, watchdog)); break; - case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break; - case Apps::Twos: currentScreen.reset(new Screens::Twos(this)); break; - case Apps::Paint: currentScreen.reset(new Screens::InfiniPaint(this, lvgl)); break; - case Apps::Paddle: currentScreen.reset(new Screens::Paddle(this, lvgl)); break; - case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break; - case Apps::Music : currentScreen.reset(new Screens::Music(this, systemTask.nimble().music())); break; - case Apps::Navigation : currentScreen.reset(new Screens::Navigation(this, systemTask.nimble().navigation())); break; - case Apps::FirmwareValidation: currentScreen.reset(new Screens::FirmwareValidation(this, validator)); break; - case Apps::Notifications: currentScreen.reset(new Screens::Notifications(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal)); break; - case Apps::HeartRate: currentScreen.reset(new Screens::HeartRate(this, heartRateController)); break; + case Apps::SysInfo: currentScreen = std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog); break; + case Apps::Meter: currentScreen = std::make_unique<Screens::Meter>(this);break; + case Apps::StopWatch: currentScreen = std::make_unique<Screens::StopWatch>(this); break; + case Apps::Twos: currentScreen = std::make_unique<Screens::Twos>(this); break; + case Apps::Paint: currentScreen = std::make_unique<Screens::InfiniPaint>(this, lvgl); break; + case Apps::Paddle: currentScreen = std::make_unique<Screens::Paddle>(this, lvgl); break; + case Apps::Brightness : currentScreen = std::make_unique<Screens::Brightness>(this, brightnessController); break; + case Apps::Music : currentScreen = std::make_unique<Screens::Music>(this, systemTask.nimble().music()); break; + case Apps::Navigation : currentScreen = std::make_unique<Screens::Navigation>(this, systemTask.nimble().navigation()); break; + case Apps::FirmwareValidation: currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator); break; + case Apps::Notifications: currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal); break; + case Apps::HeartRate: currentScreen = std::make_unique<Screens::HeartRate>(this, heartRateController); break; } nextApp = Apps::None; } diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index 9cf76953..57b8aedd 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -83,8 +83,7 @@ void DisplayApp::DisplayLogo(uint16_t color) { for(int i = 0; i < displayWidth; i++) { rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel); ulTaskNotifyTake(pdTRUE, 500); - lcd.BeginDrawBuffer(0, i, displayWidth, 1); - lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel); + lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel); } } @@ -94,8 +93,7 @@ void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) { for(int i = 0; i < barHeight; i++) { ulTaskNotifyTake(pdTRUE, 500); uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth)); - lcd.BeginDrawBuffer(0, displayWidth - barHeight + i, barWidth, 1); - lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel); + lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel); } } diff --git a/src/displayapp/fonts/Readme.md b/src/displayapp/fonts/Readme.md index 8e50c297..79b36bca 100644 --- a/src/displayapp/fonts/Readme.md +++ b/src/displayapp/fonts/Readme.md @@ -10,7 +10,7 @@ * Bpp : 1 bit-per-pixel * Do not enable font compression and horizontal subpixel hinting * Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f` - * Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd` + * Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024` * Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts` Add new symbols: diff --git a/src/displayapp/fonts/jetbrains_mono_bold_20.c b/src/displayapp/fonts/jetbrains_mono_bold_20.c index dc30104a..f4050db8 100644 --- a/src/displayapp/fonts/jetbrains_mono_bold_20.c +++ b/src/displayapp/fonts/jetbrains_mono_bold_20.c @@ -466,8 +466,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { 0x66, 0x66, 0x66, 0x6c, 0x63, /* U+417 "З" */ - 0x1f, 0x8f, 0xfd, 0xc7, 0x80, 0x70, 0x1c, 0x3e, - 0x7, 0xf0, 0xf, 0x0, 0xe0, 0x1d, 0x83, 0xb8, + 0x1f, 0xf, 0xf3, 0xc7, 0x0, 0x60, 0x1c, 0x1e, + 0x3, 0xf0, 0xe, 0x0, 0xe0, 0x1f, 0x83, 0xf8, 0xf7, 0xfc, 0x3e, 0x0, /* U+418 "И" */ @@ -615,7 +615,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { 0x70, /* U+437 "з" */ - 0x3f, 0x1f, 0xfe, 0x1c, 0x7, 0x1f, 0x7, 0xe0, + 0x3f, 0x1f, 0xfe, 0x1c, 0x7, 0x1f, 0x87, 0xe0, 0x1c, 0x7, 0xe1, 0xdf, 0xe3, 0xf0, /* U+438 "и" */ @@ -738,6 +738,15 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { 0xcf, 0x9f, 0xff, 0xf1, 0xff, 0xfc, 0x1f, 0xff, 0x1, 0xff, 0xc0, 0x1f, 0xf0, 0x0, 0x70, 0x0, + /* U+F024 "" */ + 0x70, 0x0, 0xf, 0x80, 0x0, 0xf8, 0x0, 0xf, + 0xff, 0xf, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0x7f, + 0xff, 0xf7, 0xff, 0xff, 0x7f, 0xff, 0xf7, 0xff, + 0xff, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0x7f, 0xff, + 0xf7, 0xff, 0xff, 0x7f, 0x7f, 0xe7, 0x0, 0x78, + 0x70, 0x0, 0x7, 0x0, 0x0, 0x70, 0x0, 0x7, + 0x0, 0x0, + /* U+F027 "" */ 0x0, 0xc0, 0x3, 0x80, 0xf, 0x0, 0x3e, 0xf, 0xfc, 0x9f, 0xf9, 0xbf, 0xf1, 0xff, 0xe3, 0xff, @@ -789,6 +798,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { 0xff, 0xfc, 0xff, 0xff, 0x3f, 0xff, 0xcf, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0x7e, 0x1f, 0x80, + /* U+F04D "" */ + 0x7f, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x80, + /* U+F051 "" */ 0xe0, 0x3f, 0x81, 0xfe, 0xf, 0xf8, 0x7f, 0xe3, 0xff, 0x9f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -897,6 +913,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { 0x81, 0xf8, 0x6d, 0x99, 0x9a, 0x36, 0x7, 0x80, 0xe0, 0x18, 0x2, 0x0, 0x0, + /* U+F2F2 "" */ + 0x7, 0xe0, 0x7, 0xe0, 0x1, 0x80, 0x3, 0xc0, + 0xf, 0xf2, 0x1f, 0xff, 0x3e, 0x7e, 0x7e, 0x7e, + 0xfe, 0x7e, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, + 0xfe, 0x7f, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe, + 0x3f, 0xfc, 0x1f, 0xf8, 0x7, 0xe0, + /* U+F3DD "" */ 0x40, 0x0, 0x40, 0x70, 0x0, 0x7e, 0x3c, 0x0, 0x3f, 0x8f, 0x80, 0x1f, 0x81, 0xe0, 0x1f, 0xc0, @@ -1080,7 +1103,7 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 1514, .adv_w = 192, .box_w = 11, .box_h = 17, .ofs_x = 1, .ofs_y = -3}, {.bitmap_index = 1538, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, {.bitmap_index = 1554, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1575, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1575, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, {.bitmap_index = 1595, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, {.bitmap_index = 1611, .adv_w = 192, .box_w = 9, .box_h = 19, .ofs_x = 1, .ofs_y = 0}, {.bitmap_index = 1633, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, @@ -1139,36 +1162,39 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 2498, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, {.bitmap_index = 2511, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, {.bitmap_index = 2561, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2609, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 2638, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 2693, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2732, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2775, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, - {.bitmap_index = 2803, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2851, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2890, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, - {.bitmap_index = 2918, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2966, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3019, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3038, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3088, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3124, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3172, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3215, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3253, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3291, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3329, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3367, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3405, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, - {.bitmap_index = 3443, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3472, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3538, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3587, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3637, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3697, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3750, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3805, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3858, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} + {.bitmap_index = 2609, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2659, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2688, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 2743, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2782, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2825, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 2853, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2901, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2940, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2979, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 3007, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3055, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3108, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3127, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3177, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3213, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3261, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3304, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3342, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3380, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3418, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3456, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3494, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3532, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3561, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 3599, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3665, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3714, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3764, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3824, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3877, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3932, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3985, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} }; /*--------------------- @@ -1176,10 +1202,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { *--------------------*/ static const uint16_t unicode_list_2[] = { - 0x0, 0x16, 0x26, 0x27, 0x28, 0x39, 0x47, 0x4a, - 0x4b, 0x50, 0x68, 0x94, 0x128, 0x184, 0x1e5, 0x1fb, - 0x21d, 0x23f, 0x240, 0x241, 0x242, 0x243, 0x292, 0x293, - 0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f, 0x59e, 0x59f, 0x6a8 + 0x0, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39, 0x47, + 0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x94, 0x128, 0x184, + 0x1e5, 0x1fb, 0x21d, 0x23f, 0x240, 0x241, 0x242, 0x243, + 0x292, 0x293, 0x2f1, 0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f, + 0x59e, 0x59f, 0x6a8 }; /*Collect the unicode lists and glyph_id offsets*/ @@ -1195,7 +1222,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] = }, { .range_start = 61441, .range_length = 1705, .glyph_id_start = 160, - .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 32, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY + .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 35, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY } }; diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp index 0f3286df..60039045 100644 --- a/src/displayapp/screens/ApplicationList.cpp +++ b/src/displayapp/screens/ApplicationList.cpp @@ -56,21 +56,21 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() { }; - return std::unique_ptr<Screen>(new Screens::Tile(0, app, settingsController, applications)); + return std::make_unique<Screens::Tile>(0, app, settingsController, applications); } std::unique_ptr<Screen> ApplicationList::CreateScreen2() { std::array<Screens::Tile::Applications, 6> applications { {{Symbols::map, Apps::Navigation}, - {Symbols::asterisk, Apps::Meter}, + {Symbols::stopWatch, Apps::StopWatch}, {Symbols::paintbrush, Apps::Paint}, - {Symbols::info, Apps::Notifications}, - {Symbols::paddle, Apps::Paddle}, - {"2", Apps::Twos} + {Symbols::info, Apps::Notifications}, + {Symbols::paddle, Apps::Paddle}, + {"2", Apps::Twos} } }; - return std::unique_ptr<Screen>(new Screens::Tile(1, app, settingsController, applications)); + return std::make_unique<Screens::Tile>(1, app, settingsController, applications); } std::unique_ptr<Screen> ApplicationList::CreateScreen3() { @@ -84,6 +84,6 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen3() { } }; - return std::unique_ptr<Screen>(new Screens::Tile(2, app, settingsController, applications)); + return std::make_unique<Screens::Tile>(2, app, settingsController, applications); } diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index 342dd222..69180370 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -64,20 +64,20 @@ bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() { - return std::unique_ptr<Screen>(new Screens::WatchFaceDigital(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController)); + return std::make_unique<Screens::WatchFaceDigital>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController); } std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() { - return std::unique_ptr<Screen>(new Screens::WatchFaceAnalog(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController)); + return std::make_unique<Screens::WatchFaceAnalog>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); } /* // Examples for more watch faces std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() { - return std::unique_ptr<Screen>(new Screens::WatchFaceMinimal(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController)); + return std::make_unique<Screens::WatchFaceMinimal>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); } std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() { - return std::unique_ptr<Screen>(new Screens::WatchFaceCustom(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController)); + return std::make_unique<Screens::WatchFaceCustom>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); } */
\ No newline at end of file diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 4219bac7..c903ed0f 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -17,22 +17,22 @@ Notifications::Notifications(DisplayApp *app, auto notification = notificationManager.GetLastNotification(); if(notification.valid) { currentId = notification.id; - currentItem.reset(new NotificationItem("\nNotification", + currentItem = std::make_unique<NotificationItem>("\nNotification", notification.message.data(), notification.index, notification.category, notificationManager.NbNotifications(), mode, - alertNotificationService)); + alertNotificationService); validDisplay = true; } else { - currentItem.reset(new NotificationItem("\nNotification", + currentItem = std::make_unique<NotificationItem>("\nNotification", "No notification to display", 0, notification.category, notificationManager.NbNotifications(), Modes::Preview, - alertNotificationService)); + alertNotificationService); } if(mode == Modes::Preview) { @@ -87,13 +87,13 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { currentId = previousNotification.id; currentItem.reset(nullptr); app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up); - currentItem.reset(new NotificationItem("\nNotification", + currentItem = std::make_unique<NotificationItem>("\nNotification", previousNotification.message.data(), previousNotification.index, previousNotification.category, notificationManager.NbNotifications(), mode, - alertNotificationService)); + alertNotificationService); } return true; case Pinetime::Applications::TouchEvents::SwipeDown: { @@ -109,13 +109,13 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { currentId = nextNotification.id; currentItem.reset(nullptr); app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down); - currentItem.reset(new NotificationItem("\nNotification", + currentItem = std::make_unique<NotificationItem>("\nNotification", nextNotification.message.data(), nextNotification.index, nextNotification.category, notificationManager.NbNotifications(), mode, - alertNotificationService)); + alertNotificationService); } return true; case Pinetime::Applications::TouchEvents::LongTap: { diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp new file mode 100644 index 00000000..63f18d4b --- /dev/null +++ b/src/displayapp/screens/StopWatch.cpp @@ -0,0 +1,210 @@ +#include "StopWatch.h" + +#include "Screen.h" +#include "Symbols.h" +#include "lvgl/lvgl.h" +#include "projdefs.h" +#include "FreeRTOSConfig.h" +#include "task.h" + +#include <tuple> + +using namespace Pinetime::Applications::Screens; + +// Anonymous namespace for local functions +namespace { + TimeSeparated_t convertTicksToTimeSegments(const TickType_t timeElapsed) { + const int timeElapsedMillis = (static_cast<float>(timeElapsed) / static_cast<float>(configTICK_RATE_HZ)) * 1000; + + const int milliSecs = (timeElapsedMillis % 1000) / 10; // Get only the first two digits and ignore the last + const int secs = (timeElapsedMillis / 1000) % 60; + const int mins = (timeElapsedMillis / 1000) / 60; + return TimeSeparated_t {mins, secs, milliSecs}; + } + + TickType_t calculateDelta(const TickType_t startTime, const TickType_t currentTime) { + TickType_t delta = 0; + // Take care of overflow + if (startTime > currentTime) { + delta = 0xffffffff - startTime; + delta += (currentTime + 1); + } else { + delta = currentTime - startTime; + } + return delta; + } +} + +static void play_pause_event_handler(lv_obj_t* obj, lv_event_t event) { + auto stopWatch = static_cast<StopWatch*>(obj->user_data); + stopWatch->playPauseBtnEventHandler(event); +} + +static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) { + auto stopWatch = static_cast<StopWatch*>(obj->user_data); + stopWatch->stopLapBtnEventHandler(event); +} + +StopWatch::StopWatch(DisplayApp* app) + : Screen(app), running {true}, currentState {States::Init}, currentEvent {Events::Stop}, startTime {}, oldTimeElapsed {}, + currentTimeSeparated {}, lapBuffer {}, lapNr {}, lapPressed {false} { + + time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); + lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -45); + lv_label_set_text(time, "00:00"); + + msecTime = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 108, 3); + lv_label_set_text(msecTime, "00"); + + btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); + btnPlayPause->user_data = this; + lv_obj_set_event_cb(btnPlayPause, play_pause_event_handler); + lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -10); + lv_obj_set_height(btnPlayPause, 40); + txtPlayPause = lv_label_create(btnPlayPause, nullptr); + lv_label_set_text(txtPlayPause, Symbols::play); + + lapOneText = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_align(lapOneText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 30); + lv_label_set_text(lapOneText, ""); + + lapTwoText = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55); + lv_label_set_text(lapTwoText, ""); + + // We don't want this button in the init state + btnStopLap = nullptr; +} + +StopWatch::~StopWatch() { + lv_obj_clean(lv_scr_act()); +} + +bool StopWatch::Refresh() { + // @startuml CHIP8_state + // State "Init" as init + // State "Running" as run + // State "Halted" as halt + + // [*] --> init + // init -> run : press play + // run -> run : press lap + // run --> halt : press pause + // halt --> run : press play + // halt --> init : press stop + // @enduml + // Copy paste the above plantuml text to visualize the state diagram + switch (currentState) { + // Init state when an user first opens the app + // and when a stop/reset button is pressed + case States::Init: { + if (btnStopLap) { + lv_obj_del(btnStopLap); + } + // The initial default value + lv_label_set_text(time, "00:00"); + lv_label_set_text(msecTime, "00"); + + lv_label_set_text(lapOneText, ""); + lv_label_set_text(lapTwoText, ""); + lapBuffer.clearBuffer(); + lapNr = 0; + + if (currentEvent == Events::Play) { + btnStopLap = lv_btn_create(lv_scr_act(), nullptr); + btnStopLap->user_data = this; + lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler); + lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_set_height(btnStopLap, 40); + txtStopLap = lv_label_create(btnStopLap, nullptr); + lv_label_set_text(txtStopLap, Symbols::lapsFlag); + + startTime = xTaskGetTickCount(); + currentState = States::Running; + } + break; + } + case States::Running: { + lv_label_set_text(txtPlayPause, Symbols::pause); + lv_label_set_text(txtStopLap, Symbols::lapsFlag); + + const auto timeElapsed = calculateDelta(startTime, xTaskGetTickCount()); + currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed)); + + lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); + lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.msecs); + + if (lapPressed == true) { + if (lapBuffer[1]) { + lv_label_set_text_fmt(lapOneText, "#%d %d:%d:%d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->msecs); + } + if (lapBuffer[0]) { + lv_label_set_text_fmt(lapTwoText, "#%d %d:%d:%d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->msecs); + } + // Reset the bool to avoid setting the text in each cycle until there is a change + lapPressed = false; + } + + if (currentEvent == Events::Pause) { + // Reset the start time + startTime = 0; + // Store the current time elapsed in cache + oldTimeElapsed += timeElapsed; + currentState = States::Halted; + } + break; + } + case States::Halted: { + lv_label_set_text(txtPlayPause, Symbols::play); + lv_label_set_text(txtStopLap, Symbols::stop); + + if (currentEvent == Events::Play) { + startTime = xTaskGetTickCount(); + currentState = States::Running; + } + if (currentEvent == Events::Stop) { + currentState = States::Init; + oldTimeElapsed = 0; + } + break; + } + } + return running; +} + +bool StopWatch::OnButtonPushed() { + running = false; + return true; +} + +void StopWatch::playPauseBtnEventHandler(lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + if (currentState == States::Init) { + currentEvent = Events::Play; + } else { + // Simple Toggle for play/pause + currentEvent = (currentEvent == Events::Play ? Events::Pause : Events::Play); + } + } +} + +void StopWatch::stopLapBtnEventHandler(lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + // If running, then this button is used to save laps + if (currentState == States::Running) { + lapBuffer.addLaps(currentTimeSeparated); + lapNr++; + lapPressed = true; + + } else if (currentState == States::Halted) { + currentEvent = Events::Stop; + } else { + // Not possible to reach here. Do nothing. + } + } +} diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h new file mode 100644 index 00000000..f9dd5c76 --- /dev/null +++ b/src/displayapp/screens/StopWatch.h @@ -0,0 +1,86 @@ +#pragma once + +#include "Screen.h" +#include "components/datetime/DateTimeController.h" +#include "../LittleVgl.h" + +#include "FreeRTOS.h" +#include "portmacro_cmsis.h" + +#include <array> + +namespace Pinetime::Applications::Screens { + + enum class States { Init, Running, Halted }; + + enum class Events { Play, Pause, Stop }; + + struct TimeSeparated_t { + int mins; + int secs; + int msecs; + }; + + // A simple buffer to hold the latest two laps + template <int N> struct LapTextBuffer_t { + LapTextBuffer_t() : buffer {}, currentSize {}, capacity {N}, head {-1} { + } + + void addLaps(const TimeSeparated_t& timeVal) { + head++; + head %= capacity; + buffer[head] = timeVal; + + if (currentSize < capacity) { + currentSize++; + } + } + + void clearBuffer() { + buffer = {}; + currentSize = 0; + head = -1; + } + + TimeSeparated_t* operator[](std::size_t idx) { + // Sanity check for out-of-bounds + if (idx >= 0 && idx < capacity) { + if (idx < currentSize) { + // This transformation is to ensure that head is always pointing to index 0. + const auto transformed_idx = (head - idx) % capacity; + return (&buffer[transformed_idx]); + } + } + return nullptr; + } + + private: + std::array<TimeSeparated_t, N> buffer; + uint8_t currentSize; + uint8_t capacity; + int8_t head; + }; + + class StopWatch : public Screen { + public: + StopWatch(DisplayApp* app); + ~StopWatch() override; + bool Refresh() override; + bool OnButtonPushed() override; + void playPauseBtnEventHandler(lv_event_t event); + void stopLapBtnEventHandler(lv_event_t event); + + private: + bool running; + States currentState; + Events currentEvent; + TickType_t startTime; + TickType_t oldTimeElapsed; + TimeSeparated_t currentTimeSeparated; // Holds Mins, Secs, millisecs + LapTextBuffer_t<2> lapBuffer; + int lapNr; + bool lapPressed; + lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap; + lv_obj_t *lapOneText, *lapTwoText; + }; +} diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 1a6bbd7f..9a13a755 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -36,6 +36,9 @@ namespace Pinetime { static constexpr const char* stepBackward = "\xEF\x81\x88"; static constexpr const char* play = "\xEF\x81\x8B"; static constexpr const char* pause = "\xEF\x81\x8C"; + static constexpr const char* stop = "\xEF\x81\x8D"; + static constexpr const char* stopWatch = "\xEF\x8B\xB2"; + static constexpr const char* lapsFlag = "\xEF\x80\xA4"; } } } diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index 0d6f8e5a..949fd345 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -104,14 +104,14 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() { uptimeDays, uptimeHours, uptimeMinutes, uptimeSeconds, batteryPercent, brightness, resetReason); - return std::unique_ptr<Screen>(new Screens::Label(app, t1)); + return std::make_unique<Screens::Label>(app, t1); } std::unique_ptr<Screen> SystemInfo::CreateScreen2() { auto& bleAddr = bleController.Address(); sprintf(t2, "BLE MAC: \n %02x:%02x:%02x:%02x:%02x:%02x", bleAddr[5], bleAddr[4], bleAddr[3], bleAddr[2], bleAddr[1], bleAddr[0]); - return std::unique_ptr<Screen>(new Screens::Label(app, t2)); + return std::make_unique<Screens::Label>(app, t2); } std::unique_ptr<Screen> SystemInfo::CreateScreen3() { @@ -123,5 +123,5 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() { "Source code:\n" "https://github.com/\n" " JF002/InfiniTime"); - return std::unique_ptr<Screen>(new Screens::Label(app, t3)); + return std::make_unique<Screens::Label>(app, t3); } diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index b51d48c7..66af584a 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -5,6 +5,8 @@ #include "Symbols.h" #include "NotificationIcon.h" +#include <cmath> + LV_IMG_DECLARE(bg_clock); using namespace Pinetime::Applications::Screens; diff --git a/src/libs/lvgl b/src/libs/lvgl -Subproject 69a50b97dafffddd212e4b006776b473951be7a +Subproject 1b6501dc3babf39538f4a02aa9fb14c2aaebca2 diff --git a/src/main.cpp b/src/main.cpp index b29aac71..bd4bbe79 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,8 @@ Pinetime::Logging::NrfLogger logger; Pinetime::Logging::DummyLogger logger; #endif +#include <memory> + static constexpr uint8_t pinSpiSck = 2; static constexpr uint8_t pinSpiMosi = 3; static constexpr uint8_t pinSpiMiso = 4; @@ -254,8 +256,8 @@ int main(void) { debounceTimer = xTimerCreate ("debounceTimer", 200, pdFALSE, (void *) 0, DebounceTimerCallback); - systemTask.reset(new Pinetime::System::SystemTask(spi, lcd, spiNorFlash, twiMaster, touchPanel, lvgl, batteryController, bleController, - dateTimeController, motorController, heartRateSensor, settingsController)); + systemTask = std::make_unique<Pinetime::System::SystemTask>(spi, lcd, spiNorFlash, twiMaster, touchPanel, lvgl, batteryController, bleController, + dateTimeController, motorController, heartRateSensor, settingsController); systemTask->Start(); nimble_port_init(); diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 40cd66da..9ed062e2 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -134,8 +134,7 @@ void DisplayLogo() { for(int i = 0; i < displayWidth; i++) { rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel); ulTaskNotifyTake(pdTRUE, 500); - lcd.BeginDrawBuffer(0, i, displayWidth, 1); - lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel); + lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel); } } @@ -145,8 +144,7 @@ void DisplayProgressBar(uint8_t percent, uint16_t color) { for(int i = 0; i < barHeight; i++) { ulTaskNotifyTake(pdTRUE, 500); uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth)); - lcd.BeginDrawBuffer(0, displayWidth - barHeight + i, barWidth, 1); - lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel); + lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel); } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 19a416ba..7b137f55 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -23,6 +23,8 @@ #include "drivers/Hrs3300.h" #include "main.h" +#include <memory> + using namespace Pinetime::System; void IdleTimerCallback(TimerHandle_t xTimer) { @@ -86,9 +88,9 @@ void SystemTask::Work() { settingsController.Init(); - displayApp.reset(new Pinetime::Applications::DisplayApp(lcd, lvgl, touchPanel, batteryController, bleController, + displayApp = std::make_unique<Pinetime::Applications::DisplayApp>(lcd, lvgl, touchPanel, batteryController, bleController, dateTimeController, watchdogView, *this, notificationManager, - heartRateController, settingsController)); + heartRateController, settingsController); displayApp->Start(); batteryController.Update(); @@ -96,7 +98,7 @@ void SystemTask::Work() { heartRateSensor.Init(); heartRateSensor.Disable(); - heartRateApp.reset(new Pinetime::Applications::HeartRateTask(heartRateSensor, heartRateController)); + heartRateApp = std::make_unique<Pinetime::Applications::HeartRateTask>(heartRateSensor, heartRateController); heartRateApp->Start(); |
