Merge branch 'develop' into HEAD
This commit is contained in:
@@ -1,26 +1,36 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include "BootloaderVersion.h"
|
||||
|
||||
using namespace Pinetime;
|
||||
|
||||
// NOTE : current bootloader does not export its version to the application firmware.
|
||||
// NOTE : version < 1.0.0 of bootloader does not export its version to the application firmware.
|
||||
|
||||
uint32_t BootloaderVersion::Major() {
|
||||
return 0;
|
||||
uint32_t BootloaderVersion::version = 0;
|
||||
char BootloaderVersion::versionString[BootloaderVersion::VERSION_STR_LEN] = "0.0.0";
|
||||
|
||||
const uint32_t BootloaderVersion::Major() {
|
||||
return (BootloaderVersion::version >> 16u) & 0xff;
|
||||
}
|
||||
|
||||
uint32_t BootloaderVersion::Minor() {
|
||||
return 0;
|
||||
const uint32_t BootloaderVersion::Minor() {
|
||||
return (BootloaderVersion::version >> 8u) & 0xff;
|
||||
}
|
||||
|
||||
uint32_t BootloaderVersion::Patch() {
|
||||
return 0;
|
||||
const uint32_t BootloaderVersion::Patch() {
|
||||
return BootloaderVersion::version & 0xff;
|
||||
}
|
||||
|
||||
const char* BootloaderVersion::VersionString() {
|
||||
return "0.0.0";
|
||||
return BootloaderVersion::versionString;
|
||||
}
|
||||
|
||||
bool BootloaderVersion::IsValid() {
|
||||
return false;
|
||||
const bool BootloaderVersion::IsValid() {
|
||||
return BootloaderVersion::version >= 0x00010000;
|
||||
}
|
||||
|
||||
void BootloaderVersion::SetVersion(uint32_t v) {
|
||||
BootloaderVersion::version = v;
|
||||
snprintf(BootloaderVersion::versionString, BootloaderVersion::VERSION_STR_LEN, "%ld.%ld.%ld",
|
||||
BootloaderVersion::Major(), BootloaderVersion::Minor(), BootloaderVersion::Patch());
|
||||
}
|
||||
|
@@ -3,10 +3,15 @@
|
||||
namespace Pinetime {
|
||||
class BootloaderVersion {
|
||||
public:
|
||||
static uint32_t Major();
|
||||
static uint32_t Minor();
|
||||
static uint32_t Patch();
|
||||
static const uint32_t Major();
|
||||
static const uint32_t Minor();
|
||||
static const uint32_t Patch();
|
||||
static const char* VersionString();
|
||||
static bool IsValid();
|
||||
static const bool IsValid();
|
||||
static void SetVersion(uint32_t v);
|
||||
private:
|
||||
static uint32_t version;
|
||||
static constexpr size_t VERSION_STR_LEN = 12;
|
||||
static char versionString[VERSION_STR_LEN];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -166,6 +166,13 @@ set(NIMBLE_SRC
|
||||
libs/mynewt-nimble/nimble/host/util/src/addr.c
|
||||
)
|
||||
|
||||
set(LITTLEFS_SRC
|
||||
libs/littlefs/lfs_util.h
|
||||
libs/littlefs/lfs.h
|
||||
libs/littlefs/lfs_util.c
|
||||
libs/littlefs/lfs.c
|
||||
)
|
||||
|
||||
set(LVGL_SRC
|
||||
libs/lv_conf.h
|
||||
libs/lvgl/lvgl.h
|
||||
@@ -235,6 +242,7 @@ set(LVGL_SRC
|
||||
libs/lvgl/src/lv_widgets/lv_cont.h
|
||||
libs/lvgl/src/lv_widgets/lv_cpicker.h
|
||||
libs/lvgl/src/lv_widgets/lv_dropdown.h
|
||||
libs/lvgl/src/lv_widgets/lv_gauge.h
|
||||
libs/lvgl/src/lv_widgets/lv_img.h
|
||||
libs/lvgl/src/lv_widgets/lv_imgbtn.h
|
||||
libs/lvgl/src/lv_widgets/lv_keyboard.h
|
||||
@@ -321,6 +329,7 @@ set(LVGL_SRC
|
||||
libs/lvgl/src/lv_widgets/lv_cont.c
|
||||
libs/lvgl/src/lv_widgets/lv_cpicker.c
|
||||
libs/lvgl/src/lv_widgets/lv_dropdown.c
|
||||
libs/lvgl/src/lv_widgets/lv_gauge.c
|
||||
libs/lvgl/src/lv_widgets/lv_img.c
|
||||
libs/lvgl/src/lv_widgets/lv_imgbtn.c
|
||||
libs/lvgl/src/lv_widgets/lv_keyboard.c
|
||||
@@ -396,6 +405,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/screens/FirmwareUpdate.cpp
|
||||
displayapp/screens/Music.cpp
|
||||
displayapp/screens/Navigation.cpp
|
||||
displayapp/screens/Metronome.cpp
|
||||
displayapp/screens/Motion.cpp
|
||||
displayapp/screens/FirmwareValidation.cpp
|
||||
displayapp/screens/ApplicationList.cpp
|
||||
@@ -407,6 +417,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/screens/List.cpp
|
||||
displayapp/screens/BatteryInfo.cpp
|
||||
displayapp/screens/Steps.cpp
|
||||
displayapp/screens/Timer.cpp
|
||||
|
||||
## Settings
|
||||
displayapp/screens/settings/QuickSettings.cpp
|
||||
@@ -421,6 +432,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/icons/bg_clock.c
|
||||
displayapp/screens/WatchFaceAnalog.cpp
|
||||
displayapp/screens/WatchFaceDigital.cpp
|
||||
displayapp/screens/PineTimeStyle.cpp
|
||||
|
||||
##
|
||||
|
||||
@@ -459,6 +471,8 @@ list(APPEND SOURCE_FILES
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/motor/MotorController.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
components/fs/FS.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
@@ -470,6 +484,7 @@ list(APPEND SOURCE_FILES
|
||||
displayapp/fonts/jetbrains_mono_76.c
|
||||
displayapp/fonts/jetbrains_mono_42.c
|
||||
displayapp/fonts/lv_font_sys_48.c
|
||||
displayapp/fonts/open_sans_light.c
|
||||
displayapp/lv_pinetime_theme.c
|
||||
|
||||
systemtask/SystemTask.cpp
|
||||
@@ -520,6 +535,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
||||
components/ble/HeartRateService.cpp
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
@@ -528,7 +544,6 @@ list(APPEND RECOVERY_SOURCE_FILES
|
||||
systemtask/SystemTask.cpp
|
||||
drivers/TwiMaster.cpp
|
||||
components/gfx/Gfx.cpp
|
||||
displayapp/icons/infinitime/infinitime-nb.c
|
||||
components/rle/RleDecoder.cpp
|
||||
components/heartrate/HeartRateController.cpp
|
||||
heartratetask/HeartRateTask.cpp
|
||||
@@ -536,6 +551,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
||||
components/heartrate/Biquad.cpp
|
||||
components/heartrate/Ptagc.cpp
|
||||
components/motor/MotorController.cpp
|
||||
components/fs/FS.cpp
|
||||
)
|
||||
|
||||
list(APPEND RECOVERYLOADER_SOURCE_FILES
|
||||
@@ -555,7 +571,6 @@ list(APPEND RECOVERYLOADER_SOURCE_FILES
|
||||
drivers/St7789.cpp
|
||||
components/brightness/BrightnessController.cpp
|
||||
|
||||
displayapp/icons/infinitime/infinitime-nb.c
|
||||
recoveryLoader.cpp
|
||||
)
|
||||
|
||||
@@ -589,7 +604,9 @@ set(INCLUDE_FILES
|
||||
displayapp/Apps.h
|
||||
displayapp/screens/Notifications.h
|
||||
displayapp/screens/HeartRate.h
|
||||
displayapp/screens/Metronome.h
|
||||
displayapp/screens/Motion.h
|
||||
displayapp/screens/Timer.h
|
||||
drivers/St7789.h
|
||||
drivers/SpiNorFlash.h
|
||||
drivers/SpiMaster.h
|
||||
@@ -619,6 +636,7 @@ set(INCLUDE_FILES
|
||||
components/ble/BleClient.h
|
||||
components/ble/HeartRateService.h
|
||||
components/settings/Settings.h
|
||||
components/timer/TimerController.h
|
||||
drivers/Cst816s.h
|
||||
FreeRTOS/portmacro.h
|
||||
FreeRTOS/portmacro_cmsis.h
|
||||
@@ -739,16 +757,18 @@ link_directories(
|
||||
)
|
||||
|
||||
|
||||
set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wno-unknown-pragmas -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type)
|
||||
set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wno-unknown-pragmas -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type -fstack-usage -fno-exceptions -fno-non-call-exceptions)
|
||||
add_definitions(-DCONFIG_GPIO_AS_PINRESET)
|
||||
add_definitions(-DDEBUG)
|
||||
add_definitions(-DNIMBLE_CFG_CONTROLLER)
|
||||
add_definitions(-DOS_CPUTIME_FREQ)
|
||||
add_definitions(-DNRF52 -DNRF52832 -DNRF52832_XXAA -DNRF52_PAN_74 -DNRF52_PAN_64 -DNRF52_PAN_12 -DNRF52_PAN_58 -DNRF52_PAN_54 -DNRF52_PAN_31 -DNRF52_PAN_51 -DNRF52_PAN_36 -DNRF52_PAN_15 -DNRF52_PAN_20 -DNRF52_PAN_55 -DBOARD_PCA10040)
|
||||
add_definitions(-DFREERTOS)
|
||||
add_definitions(-DDEBUG_NRF_USER)
|
||||
add_definitions(-D__STACK_SIZE=8192)
|
||||
add_definitions(-D__HEAP_SIZE=8192)
|
||||
add_definitions(-D__STACK_SIZE=1024)
|
||||
add_definitions(-D__HEAP_SIZE=4096)
|
||||
|
||||
# NOTE : Add the following defines to enable debug mode of the NRF SDK:
|
||||
#add_definitions(-DDEBUG)
|
||||
#add_definitions(-DDEBUG_NRF_USER)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
@@ -759,10 +779,10 @@ add_library(nrf-sdk STATIC ${SDK_SOURCE_FILES})
|
||||
target_include_directories(nrf-sdk SYSTEM PUBLIC . ../)
|
||||
target_include_directories(nrf-sdk SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
|
||||
target_compile_options(nrf-sdk PRIVATE
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -771,10 +791,10 @@ add_library(nimble STATIC ${NIMBLE_SRC} ${TINYCRYPT_SRC})
|
||||
target_include_directories(nimble SYSTEM PUBLIC . ../)
|
||||
target_include_directories(nimble SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
|
||||
target_compile_options(nimble PRIVATE
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -Wno-unused-but-set-variable -Wno-maybe-uninitialized>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -783,10 +803,22 @@ add_library(lvgl STATIC ${LVGL_SRC})
|
||||
target_include_directories(lvgl SYSTEM PUBLIC . ../)
|
||||
target_include_directories(lvgl SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
|
||||
target_compile_options(lvgl PRIVATE
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
# LITTLEFS_SRC
|
||||
add_library(littlefs STATIC ${LITTLEFS_SRC})
|
||||
target_include_directories(littlefs SYSTEM PUBLIC . ../)
|
||||
target_include_directories(littlefs SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
|
||||
target_compile_options(littlefs PRIVATE
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-unused-function -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-unused-function -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-unused-function -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-unused-function -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -796,12 +828,12 @@ set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime
|
||||
set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld")
|
||||
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES})
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME})
|
||||
target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl)
|
||||
target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs)
|
||||
target_compile_options(${EXECUTABLE_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -825,13 +857,13 @@ set(IMAGE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERSION_
|
||||
set(DFU_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
|
||||
set(NRF5_LINKER_SCRIPT_MCUBOOT "${CMAKE_SOURCE_DIR}/gcc_nrf52-mcuboot.ld")
|
||||
add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl)
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs)
|
||||
set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -861,14 +893,14 @@ endif()
|
||||
set(EXECUTABLE_RECOVERY_NAME "pinetime-recovery")
|
||||
set(EXECUTABLE_RECOVERY_FILE_NAME ${EXECUTABLE_RECOVERY_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
add_executable(${EXECUTABLE_RECOVERY_NAME} ${RECOVERY_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk)
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs)
|
||||
set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_FILE_NAME})
|
||||
target_compile_definitions(${EXECUTABLE_RECOVERY_NAME} PUBLIC "PINETIME_IS_RECOVERY")
|
||||
target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -891,14 +923,14 @@ set(EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-${
|
||||
set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.bin)
|
||||
set(DFU_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
|
||||
add_executable(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} ${RECOVERY_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk)
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs)
|
||||
set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME})
|
||||
target_compile_definitions(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC "PINETIME_IS_RECOVERY")
|
||||
target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
@@ -932,10 +964,10 @@ add_executable(${EXECUTABLE_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_RECOVERYLOADER_NAME} nrf-sdk)
|
||||
set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERYLOADER_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
target_include_directories(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC
|
||||
@@ -965,10 +997,10 @@ add_executable(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} nrf-sdk)
|
||||
set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
target_include_directories(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC
|
||||
|
@@ -294,6 +294,25 @@ static void vPortEnableVFP( void )
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
uint32_t ulSetInterruptMaskFromISR( void )
|
||||
{
|
||||
__asm volatile (
|
||||
" mrs r0, PRIMASK \n"
|
||||
" cpsid i \n"
|
||||
" bx lr "
|
||||
::: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask )
|
||||
{
|
||||
__asm volatile (
|
||||
" msr PRIMASK, r0 \n"
|
||||
" bx lr "
|
||||
::: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#if ( configASSERT_DEFINED == 1 )
|
||||
|
||||
void vPortValidateInterruptPriority( void )
|
||||
@@ -354,24 +373,4 @@ static void vPortEnableVFP( void )
|
||||
configASSERT( NVIC_GetPriorityGrouping() <= ulMaxPRIGROUPValue );
|
||||
}
|
||||
|
||||
uint32_t ulSetInterruptMaskFromISR( void )
|
||||
{
|
||||
__asm volatile (
|
||||
" mrs r0, PRIMASK \n"
|
||||
" cpsid i \n"
|
||||
" bx lr "
|
||||
::: "memory"
|
||||
);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask )
|
||||
{
|
||||
__asm volatile (
|
||||
" msr PRIMASK, r0 \n"
|
||||
" bx lr "
|
||||
::: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif /* configASSERT_DEFINED */
|
||||
|
@@ -62,7 +62,7 @@
|
||||
#define configTICK_RATE_HZ 1024
|
||||
#define configMAX_PRIORITIES (3)
|
||||
#define configMINIMAL_STACK_SIZE (120)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 16)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 17)
|
||||
#define configMAX_TASK_NAME_LEN (4)
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
@@ -77,7 +77,7 @@
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 1
|
||||
|
||||
/* Hook function related definitions. */
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
|
@@ -8,11 +8,13 @@ namespace Pinetime {
|
||||
static constexpr uint32_t Major() {return major;}
|
||||
static constexpr uint32_t Minor() {return minor;}
|
||||
static constexpr uint32_t Patch() {return patch;}
|
||||
static constexpr const char* GitCommitHash() {return commitHash;}
|
||||
static constexpr const char* VersionString() {return versionString;}
|
||||
private:
|
||||
static constexpr uint32_t major = @PROJECT_VERSION_MAJOR@;
|
||||
static constexpr uint32_t minor = @PROJECT_VERSION_MINOR@;
|
||||
static constexpr uint32_t patch = @PROJECT_VERSION_PATCH@;
|
||||
static constexpr const char* commitHash = "@PROJECT_GIT_COMMIT_HASH@";
|
||||
static constexpr const char* versionString = "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@";
|
||||
};
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
#include "BatteryController.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <nrfx_saadc.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
@@ -14,17 +12,16 @@ Battery::Battery() {
|
||||
}
|
||||
|
||||
void Battery::Init() {
|
||||
nrf_gpio_cfg_input(chargingPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(powerPresentPin, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(chargingPin, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Pullup);
|
||||
}
|
||||
|
||||
void Battery::Update() {
|
||||
|
||||
isCharging = !nrf_gpio_pin_read(chargingPin);
|
||||
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
|
||||
|
||||
if (isReading)
|
||||
if (isReading) {
|
||||
return;
|
||||
}
|
||||
// Non blocking read
|
||||
samples = 0;
|
||||
isReading = true;
|
||||
@@ -33,13 +30,13 @@ void Battery::Update() {
|
||||
nrfx_saadc_sample();
|
||||
}
|
||||
|
||||
void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) {
|
||||
void Battery::AdcCallbackStatic(nrfx_saadc_evt_t const* event) {
|
||||
instance->SaadcEventHandler(event);
|
||||
}
|
||||
|
||||
void Battery::SaadcInit() {
|
||||
nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG;
|
||||
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic));
|
||||
APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, AdcCallbackStatic));
|
||||
|
||||
nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
|
||||
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
|
||||
@@ -55,23 +52,23 @@ void Battery::SaadcInit() {
|
||||
}
|
||||
|
||||
void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
|
||||
|
||||
const float battery_max = 4.18; // maximum voltage of battery ( max charging voltage is 4.21 )
|
||||
const float battery_min = 3.20; // minimum voltage of battery before shutdown ( depends on the battery )
|
||||
const uint16_t battery_max = 4180; // maximum voltage of battery ( max charging voltage is 4.21 )
|
||||
const uint16_t battery_min = 3200; // minimum voltage of battery before shutdown ( depends on the battery )
|
||||
|
||||
if (p_event->type == NRFX_SAADC_EVT_DONE) {
|
||||
|
||||
APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1));
|
||||
|
||||
voltage = (static_cast<float>(p_event->data.done.p_buffer[0]) * 2.04f) / (1024 / 3.0f);
|
||||
voltage = roundf(voltage * 100) / 100;
|
||||
|
||||
percentRemaining = static_cast<int>(((voltage - battery_min) / (battery_max - battery_min)) * 100);
|
||||
|
||||
// A hardware voltage divider divides the battery voltage by 2
|
||||
// ADC gain is 1/5
|
||||
// thus adc_voltage = battery_voltage / 2 * gain = battery_voltage / 10
|
||||
// reference_voltage is 0.6V
|
||||
// p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024
|
||||
voltage = p_event->data.done.p_buffer[0] * 6000 / 1024;
|
||||
percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min);
|
||||
percentRemaining = std::max(percentRemaining, 0);
|
||||
percentRemaining = std::min(percentRemaining, 100);
|
||||
|
||||
percentRemainingBuffer.insert(percentRemaining);
|
||||
percentRemainingBuffer.Insert(percentRemaining);
|
||||
|
||||
samples++;
|
||||
if (samples > percentRemainingSamples) {
|
||||
|
@@ -19,7 +19,7 @@ namespace Pinetime {
|
||||
insert member function overwrites the next data to the current
|
||||
HEAD and moves the HEAD to the newly inserted value.
|
||||
*/
|
||||
void insert(const int num) {
|
||||
void Insert(const uint8_t num) {
|
||||
head %= cap;
|
||||
arr[head++] = num;
|
||||
if (sz != cap) {
|
||||
@@ -27,13 +27,13 @@ namespace Pinetime {
|
||||
}
|
||||
}
|
||||
|
||||
int GetAverage() const {
|
||||
uint8_t GetAverage() const {
|
||||
int sum = std::accumulate(arr.begin(), arr.end(), 0);
|
||||
return (sum / sz);
|
||||
return static_cast<uint8_t>(sum / sz);
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<int, N> arr; /**< internal array used to store the values*/
|
||||
std::array<uint8_t, N> arr; /**< internal array used to store the values*/
|
||||
uint8_t sz; /**< The current size of the array.*/
|
||||
uint8_t cap; /**< Total capacity of the CircBuffer.*/
|
||||
uint8_t head; /**< The current head of the CircBuffer*/
|
||||
@@ -46,17 +46,21 @@ namespace Pinetime {
|
||||
void Init();
|
||||
void Update();
|
||||
|
||||
int PercentRemaining() const {
|
||||
return percentRemainingBuffer.GetAverage();
|
||||
uint8_t PercentRemaining() const {
|
||||
auto avg = percentRemainingBuffer.GetAverage();
|
||||
avg = std::min(avg, static_cast<uint8_t>(100));
|
||||
avg = std::max(avg, static_cast<uint8_t>(0));
|
||||
return avg;
|
||||
}
|
||||
|
||||
float Voltage() const {
|
||||
uint16_t Voltage() const {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
bool IsCharging() const {
|
||||
return isCharging;
|
||||
}
|
||||
|
||||
bool IsPowerPresent() const {
|
||||
return isPowerPresent;
|
||||
}
|
||||
@@ -71,7 +75,7 @@ namespace Pinetime {
|
||||
static constexpr uint32_t chargingPin = 12;
|
||||
static constexpr uint32_t powerPresentPin = 19;
|
||||
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
||||
float voltage = 0.0f;
|
||||
uint16_t voltage = 0;
|
||||
int percentRemaining = -1;
|
||||
|
||||
bool isCharging = false;
|
||||
@@ -80,10 +84,10 @@ namespace Pinetime {
|
||||
void SaadcInit();
|
||||
|
||||
void SaadcEventHandler(nrfx_saadc_evt_t const* p_event);
|
||||
static void adcCallbackStatic(nrfx_saadc_evt_t const* event);
|
||||
static void AdcCallbackStatic(nrfx_saadc_evt_t const* event);
|
||||
|
||||
bool isReading = false;
|
||||
uint8_t samples = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -159,7 +159,7 @@ void AlertNotificationClient::OnNotification(ble_gap_event* event) {
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
|
||||
notificationManager.Push(std::move(notif));
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::OnNewNotification);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -79,7 +79,7 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle
|
||||
break;
|
||||
}
|
||||
|
||||
auto event = Pinetime::System::SystemTask::Messages::OnNewNotification;
|
||||
auto event = Pinetime::System::Messages::OnNewNotification;
|
||||
notificationManager.Push(std::move(notif));
|
||||
systemTask.PushMessage(event);
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte
|
||||
characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid,
|
||||
.access_cb = BatteryInformationServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &batteryLevelHandle},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
@@ -48,4 +48,8 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
void BatteryInformationService::NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level) {
|
||||
auto* om = ble_hs_mbuf_from_flat(&level, 1);
|
||||
ble_gattc_notify_custom(connectionHandle, batteryLevelHandle, om);
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ namespace Pinetime {
|
||||
void Init();
|
||||
|
||||
int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
|
||||
void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level);
|
||||
private:
|
||||
Controllers::Battery& batteryController;
|
||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||
|
@@ -121,6 +121,11 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
NRF_LOG_INFO(
|
||||
"[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
|
||||
|
||||
// wait until SystemTask has finished waking up all devices
|
||||
while (systemTask.IsSleeping()) {
|
||||
vTaskDelay(50); // 50ms
|
||||
}
|
||||
|
||||
dfuImage.Erase();
|
||||
|
||||
uint8_t data[] {16, 1, 1};
|
||||
@@ -205,7 +210,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Running);
|
||||
bleController.FirmwareUpdateTotalBytes(0xffffffffu);
|
||||
bleController.FirmwareUpdateCurrentBytes(0);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateStarted);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::BleFirmwareUpdateStarted);
|
||||
return 0;
|
||||
} else {
|
||||
NRF_LOG_INFO("[DFU] -> Start DFU, mode %d not supported!", imageType);
|
||||
@@ -261,13 +266,14 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
static_cast<uint8_t>(ErrorCodes::NoError)};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
} else {
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||
NRF_LOG_INFO("Image Error : bad CRC");
|
||||
|
||||
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
|
||||
static_cast<uint8_t>(Opcodes::ValidateFirmware),
|
||||
static_cast<uint8_t>(ErrorCodes::CrcError)};
|
||||
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||
Reset();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -278,10 +284,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
return 0;
|
||||
}
|
||||
NRF_LOG_INFO("[DFU] -> Activate image and reset!");
|
||||
bleController.StopFirmwareUpdate();
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished);
|
||||
Reset();
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
|
||||
Reset();
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
@@ -289,6 +293,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
}
|
||||
|
||||
void DfuService::OnTimeout() {
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -302,9 +307,8 @@ void DfuService::Reset() {
|
||||
applicationSize = 0;
|
||||
expectedCrc = 0;
|
||||
notificationManager.Reset();
|
||||
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
|
||||
bleController.StopFirmwareUpdate();
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleFirmwareUpdateFinished);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::BleFirmwareUpdateFinished);
|
||||
}
|
||||
|
||||
DfuService::NotificationManager::NotificationManager() {
|
||||
|
@@ -67,7 +67,7 @@ int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
|
||||
notificationManager.Push(std::move(notif));
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::OnNewNotification);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2020 JF, Adam Pigg, Avamander
|
||||
/* Copyright (C) 2020-2021 JF, Adam Pigg, Avamander
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
@@ -18,132 +18,103 @@
|
||||
#include "MusicService.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto musicService = static_cast<Pinetime::Controllers::MusicService*>(arg);
|
||||
return musicService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
namespace {
|
||||
// 0000yyxx-78fc-48fe-8e23-433b3a1942d0
|
||||
constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
|
||||
return ble_uuid128_t{
|
||||
.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x00, 0x00 }
|
||||
};
|
||||
}
|
||||
|
||||
// 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
constexpr ble_uuid128_t BaseUuid() {
|
||||
return CharUuid(0x00, 0x00);
|
||||
}
|
||||
|
||||
constexpr ble_uuid128_t msUuid {BaseUuid()};
|
||||
|
||||
constexpr ble_uuid128_t msEventCharUuid {CharUuid(0x01, 0x00)};
|
||||
constexpr ble_uuid128_t msStatusCharUuid {CharUuid(0x02, 0x00)};
|
||||
constexpr ble_uuid128_t msArtistCharUuid {CharUuid(0x03, 0x00)};
|
||||
constexpr ble_uuid128_t msTrackCharUuid {CharUuid(0x04, 0x00)};
|
||||
constexpr ble_uuid128_t msAlbumCharUuid {CharUuid(0x05, 0x00)};
|
||||
constexpr ble_uuid128_t msPositionCharUuid {CharUuid(0x06, 0x00)};
|
||||
constexpr ble_uuid128_t msTotalLengthCharUuid {CharUuid(0x07, 0x00)};
|
||||
constexpr ble_uuid128_t msTrackNumberCharUuid {CharUuid(0x08, 0x00)};
|
||||
constexpr ble_uuid128_t msTrackTotalCharUuid {CharUuid(0x09, 0x00)};
|
||||
constexpr ble_uuid128_t msPlaybackSpeedCharUuid {CharUuid(0x0a, 0x00)};
|
||||
constexpr ble_uuid128_t msRepeatCharUuid {CharUuid(0x0b, 0x00)};
|
||||
constexpr ble_uuid128_t msShuffleCharUuid {CharUuid(0x0c, 0x00)};
|
||||
|
||||
int MusicCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
return static_cast<Pinetime::Controllers::MusicService*>(arg)->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
}
|
||||
|
||||
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||
msUuid.value[14] = msId[0];
|
||||
msUuid.value[15] = msId[1];
|
||||
|
||||
msEventCharUuid.value[12] = msEventCharId[0];
|
||||
msEventCharUuid.value[13] = msEventCharId[1];
|
||||
msEventCharUuid.value[14] = msId[0];
|
||||
msEventCharUuid.value[15] = msId[1];
|
||||
|
||||
msStatusCharUuid.value[12] = msStatusCharId[0];
|
||||
msStatusCharUuid.value[13] = msStatusCharId[1];
|
||||
msStatusCharUuid.value[14] = msId[0];
|
||||
msStatusCharUuid.value[15] = msId[1];
|
||||
|
||||
msTrackCharUuid.value[12] = msTrackCharId[0];
|
||||
msTrackCharUuid.value[13] = msTrackCharId[1];
|
||||
msTrackCharUuid.value[14] = msId[0];
|
||||
msTrackCharUuid.value[15] = msId[1];
|
||||
|
||||
msArtistCharUuid.value[12] = msArtistCharId[0];
|
||||
msArtistCharUuid.value[13] = msArtistCharId[1];
|
||||
msArtistCharUuid.value[14] = msId[0];
|
||||
msArtistCharUuid.value[15] = msId[1];
|
||||
|
||||
msAlbumCharUuid.value[12] = msAlbumCharId[0];
|
||||
msAlbumCharUuid.value[13] = msAlbumCharId[1];
|
||||
msAlbumCharUuid.value[14] = msId[0];
|
||||
msAlbumCharUuid.value[15] = msId[1];
|
||||
|
||||
msPositionCharUuid.value[12] = msPositionCharId[0];
|
||||
msPositionCharUuid.value[13] = msPositionCharId[1];
|
||||
msPositionCharUuid.value[14] = msId[0];
|
||||
msPositionCharUuid.value[15] = msId[1];
|
||||
|
||||
msTotalLengthCharUuid.value[12] = msTotalLengthCharId[0];
|
||||
msTotalLengthCharUuid.value[13] = msTotalLengthCharId[1];
|
||||
msTotalLengthCharUuid.value[14] = msId[0];
|
||||
msTotalLengthCharUuid.value[15] = msId[1];
|
||||
|
||||
msTrackNumberCharUuid.value[12] = msTrackNumberCharId[0];
|
||||
msTrackNumberCharUuid.value[13] = msTrackNumberCharId[1];
|
||||
msTrackNumberCharUuid.value[14] = msId[0];
|
||||
msTrackNumberCharUuid.value[15] = msId[1];
|
||||
|
||||
msTrackTotalCharUuid.value[12] = msTrackTotalCharId[0];
|
||||
msTrackTotalCharUuid.value[13] = msTrackTotalCharId[1];
|
||||
msTrackTotalCharUuid.value[14] = msId[0];
|
||||
msTrackTotalCharUuid.value[15] = msId[1];
|
||||
|
||||
msPlaybackSpeedCharUuid.value[12] = msPlaybackSpeedCharId[0];
|
||||
msPlaybackSpeedCharUuid.value[13] = msPlaybackSpeedCharId[1];
|
||||
msPlaybackSpeedCharUuid.value[14] = msId[0];
|
||||
msPlaybackSpeedCharUuid.value[15] = msId[1];
|
||||
|
||||
msRepeatCharUuid.value[12] = msRepeatCharId[0];
|
||||
msRepeatCharUuid.value[13] = msRepeatCharId[1];
|
||||
msRepeatCharUuid.value[14] = msId[0];
|
||||
msRepeatCharUuid.value[15] = msId[1];
|
||||
|
||||
msShuffleCharUuid.value[12] = msShuffleCharId[0];
|
||||
msShuffleCharUuid.value[13] = msShuffleCharId[1];
|
||||
msShuffleCharUuid.value[14] = msId[0];
|
||||
msShuffleCharUuid.value[15] = msId[1];
|
||||
|
||||
characteristicDefinition[0] = {.uuid = (ble_uuid_t*) (&msEventCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
characteristicDefinition[0] = {.uuid = &msEventCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &eventHandle};
|
||||
characteristicDefinition[1] = {
|
||||
.uuid = (ble_uuid_t*) (&msStatusCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[2] = {
|
||||
.uuid = (ble_uuid_t*) (&msTrackCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[3] = {
|
||||
.uuid = (ble_uuid_t*) (&msArtistCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[4] = {
|
||||
.uuid = (ble_uuid_t*) (&msAlbumCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[5] = {
|
||||
.uuid = (ble_uuid_t*) (&msPositionCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[6] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
characteristicDefinition[1] = {.uuid = &msStatusCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[7] = {.uuid = (ble_uuid_t*) (&msTotalLengthCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
characteristicDefinition[2] = {.uuid = &msTrackCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[8] = {.uuid = (ble_uuid_t*) (&msTrackNumberCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
characteristicDefinition[3] = {.uuid = &msArtistCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[9] = {.uuid = (ble_uuid_t*) (&msTrackTotalCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
characteristicDefinition[4] = {.uuid = &msAlbumCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[10] = {.uuid = (ble_uuid_t*) (&msPlaybackSpeedCharUuid),
|
||||
.access_cb = MSCallback,
|
||||
characteristicDefinition[5] = {.uuid = &msPositionCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[6] = {.uuid = &msTotalLengthCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[7] = {.uuid = &msTotalLengthCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[8] = {.uuid = &msTrackNumberCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[9] = {.uuid = &msTrackTotalCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[10] = {.uuid = &msPlaybackSpeedCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[11] = {.uuid = &msRepeatCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[12] = {.uuid = &msShuffleCharUuid.u,
|
||||
.access_cb = MusicCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[11] = {
|
||||
.uuid = (ble_uuid_t*) (&msRepeatCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[12] = {
|
||||
.uuid = (ble_uuid_t*) (&msShuffleCharUuid), .access_cb = MSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
characteristicDefinition[13] = {0};
|
||||
|
||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = (ble_uuid_t*) &msUuid, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[0] = {
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &msUuid.u, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[1] = {0};
|
||||
|
||||
artistName = "Waiting for";
|
||||
albumName = "";
|
||||
trackName = "track information..";
|
||||
playing = false;
|
||||
repeat = false;
|
||||
shuffle = false;
|
||||
playbackSpeed = 1.0f;
|
||||
trackProgress = 0;
|
||||
trackLength = 0;
|
||||
}
|
||||
|
||||
void Pinetime::Controllers::MusicService::Init() {
|
||||
int res = 0;
|
||||
uint8_t res = 0;
|
||||
res = ble_gatts_count_cfg(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
@@ -152,60 +123,67 @@ void Pinetime::Controllers::MusicService::Init() {
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t data[notifSize + 1];
|
||||
char data[notifSize + 1];
|
||||
data[notifSize] = '\0';
|
||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||
char* s = (char*) &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msArtistCharUuid) == 0) {
|
||||
char* s = &data[0];
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, &msArtistCharUuid.u) == 0) {
|
||||
artistName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTrackCharUuid.u) == 0) {
|
||||
trackName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msAlbumCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msAlbumCharUuid.u) == 0) {
|
||||
albumName = s;
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msStatusCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msStatusCharUuid.u) == 0) {
|
||||
playing = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msRepeatCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msRepeatCharUuid.u) == 0) {
|
||||
repeat = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msShuffleCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msShuffleCharUuid.u) == 0) {
|
||||
shuffle = s[0];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPositionCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msPositionCharUuid.u) == 0) {
|
||||
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTotalLengthCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTotalLengthCharUuid.u) == 0) {
|
||||
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackNumberCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTrackNumberCharUuid.u) == 0) {
|
||||
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msTrackTotalCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTrackTotalCharUuid.u) == 0) {
|
||||
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t*) &msPlaybackSpeedCharUuid) == 0) {
|
||||
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msPlaybackSpeedCharUuid.u) == 0) {
|
||||
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::MusicService::getAlbum() {
|
||||
std::string Pinetime::Controllers::MusicService::getAlbum() const {
|
||||
return albumName;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::MusicService::getArtist() {
|
||||
std::string Pinetime::Controllers::MusicService::getArtist() const {
|
||||
return artistName;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::MusicService::getTrack() {
|
||||
std::string Pinetime::Controllers::MusicService::getTrack() const {
|
||||
return trackName;
|
||||
}
|
||||
|
||||
bool Pinetime::Controllers::MusicService::isPlaying() {
|
||||
bool Pinetime::Controllers::MusicService::isPlaying() const {
|
||||
return playing;
|
||||
}
|
||||
|
||||
float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
|
||||
float Pinetime::Controllers::MusicService::getPlaybackSpeed() const {
|
||||
return playbackSpeed;
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::getProgress() const {
|
||||
return trackProgress;
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::getTrackLength() const {
|
||||
return trackLength;
|
||||
}
|
||||
|
||||
void Pinetime::Controllers::MusicService::event(char event) {
|
||||
auto* om = ble_hs_mbuf_from_flat(&event, 1);
|
||||
|
||||
@@ -217,11 +195,3 @@ void Pinetime::Controllers::MusicService::event(char event) {
|
||||
|
||||
ble_gattc_notify_custom(connectionHandle, eventHandle, om);
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::getProgress() {
|
||||
return trackProgress;
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::MusicService::getTrackLength() {
|
||||
return trackLength;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2020 JF, Adam Pigg, Avamander
|
||||
/* Copyright (C) 2020-2021 JF, Adam Pigg, Avamander
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
@@ -26,16 +26,11 @@
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
// 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
#define MUSIC_SERVICE_UUID_BASE \
|
||||
{ 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
|
||||
class MusicService {
|
||||
public:
|
||||
explicit MusicService(Pinetime::System::SystemTask& system);
|
||||
@@ -46,19 +41,19 @@ namespace Pinetime {
|
||||
|
||||
void event(char event);
|
||||
|
||||
std::string getArtist();
|
||||
std::string getArtist() const;
|
||||
|
||||
std::string getTrack();
|
||||
std::string getTrack() const;
|
||||
|
||||
std::string getAlbum();
|
||||
std::string getAlbum() const;
|
||||
|
||||
int getProgress();
|
||||
int getProgress() const;
|
||||
|
||||
int getTrackLength();
|
||||
int getTrackLength() const;
|
||||
|
||||
float getPlaybackSpeed();
|
||||
float getPlaybackSpeed() const;
|
||||
|
||||
bool isPlaying();
|
||||
bool isPlaying() const;
|
||||
|
||||
static const char EVENT_MUSIC_OPEN = 0xe0;
|
||||
static const char EVENT_MUSIC_PLAY = 0x00;
|
||||
@@ -71,55 +66,26 @@ namespace Pinetime {
|
||||
enum MusicStatus { NotPlaying = 0x00, Playing = 0x01 };
|
||||
|
||||
private:
|
||||
static constexpr uint8_t msId[2] = {0x00, 0x00};
|
||||
static constexpr uint8_t msEventCharId[2] = {0x01, 0x00};
|
||||
static constexpr uint8_t msStatusCharId[2] = {0x02, 0x00};
|
||||
static constexpr uint8_t msArtistCharId[2] = {0x03, 0x00};
|
||||
static constexpr uint8_t msTrackCharId[2] = {0x04, 0x00};
|
||||
static constexpr uint8_t msAlbumCharId[2] = {0x05, 0x00};
|
||||
static constexpr uint8_t msPositionCharId[2] = {0x06, 0x00};
|
||||
static constexpr uint8_t msTotalLengthCharId[2] = {0x07, 0x00};
|
||||
static constexpr uint8_t msTrackNumberCharId[2] = {0x08, 0x00};
|
||||
static constexpr uint8_t msTrackTotalCharId[2] = {0x09, 0x00};
|
||||
static constexpr uint8_t msPlaybackSpeedCharId[2] = {0x0a, 0x00};
|
||||
static constexpr uint8_t msRepeatCharId[2] = {0x0b, 0x00};
|
||||
static constexpr uint8_t msShuffleCharId[2] = {0x0c, 0x00};
|
||||
|
||||
ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
|
||||
ble_uuid128_t msEventCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msStatusCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msArtistCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msAlbumCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msPositionCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTotalLengthCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackNumberCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msTrackTotalCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msPlaybackSpeedCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msRepeatCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
ble_uuid128_t msShuffleCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = MUSIC_SERVICE_UUID_BASE};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[14];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t eventHandle;
|
||||
uint16_t eventHandle {};
|
||||
|
||||
std::string artistName;
|
||||
std::string albumName;
|
||||
std::string trackName;
|
||||
std::string artistName {"Waiting for"};
|
||||
std::string albumName {};
|
||||
std::string trackName {"track information.."};
|
||||
|
||||
bool playing;
|
||||
bool playing {false};
|
||||
|
||||
int trackProgress;
|
||||
int trackLength;
|
||||
int trackNumber;
|
||||
int tracksTotal;
|
||||
int trackProgress {0};
|
||||
int trackLength {0};
|
||||
int trackNumber {};
|
||||
int tracksTotal {};
|
||||
|
||||
float playbackSpeed;
|
||||
float playbackSpeed {1.0f};
|
||||
|
||||
bool repeat;
|
||||
bool shuffle;
|
||||
bool repeat {false};
|
||||
bool shuffle {false};
|
||||
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
|
@@ -149,7 +149,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
||||
bleController.Disconnect();
|
||||
} else {
|
||||
bleController.Connect();
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::BleConnected);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::BleConnected);
|
||||
connectionHandle = event->connect.conn_handle;
|
||||
// Service discovery is deffered via systemtask
|
||||
}
|
||||
@@ -235,3 +235,9 @@ void NimbleController::StartDiscovery() {
|
||||
uint16_t NimbleController::connHandle() {
|
||||
return connectionHandle;
|
||||
}
|
||||
|
||||
void NimbleController::NotifyBatteryLevel(uint8_t level) {
|
||||
if(connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
batteryInformationService.NotifyBatteryLevel(connectionHandle, level);
|
||||
}
|
||||
}
|
||||
|
@@ -70,6 +70,7 @@ namespace Pinetime {
|
||||
};
|
||||
|
||||
uint16_t connHandle();
|
||||
void NotifyBatteryLevel(uint8_t level);
|
||||
|
||||
private:
|
||||
static constexpr const char* deviceName = "InfiniTime";
|
||||
@@ -92,7 +93,7 @@ namespace Pinetime {
|
||||
HeartRateService heartRateService;
|
||||
|
||||
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
||||
uint16_t connectionHandle = 0;
|
||||
uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
|
||||
ble_uuid128_t dfuServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
|
@@ -5,9 +5,6 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
DateTime::DateTime(System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
}
|
||||
|
||||
void DateTime::SetTime(
|
||||
uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) {
|
||||
std::tm tm = {
|
||||
@@ -70,7 +67,8 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
||||
// Notify new day to SystemTask
|
||||
if (hour == 0 and not isMidnightAlreadyNotified) {
|
||||
isMidnightAlreadyNotified = true;
|
||||
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
|
||||
if(systemTask != nullptr)
|
||||
systemTask->PushMessage(System::Messages::OnNewDay);
|
||||
} else if (hour != 0) {
|
||||
isMidnightAlreadyNotified = false;
|
||||
}
|
||||
@@ -104,6 +102,10 @@ const char* DateTime::DayOfWeekShortToStringLow() {
|
||||
return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek];
|
||||
}
|
||||
|
||||
void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
}
|
||||
|
||||
char const* DateTime::DaysStringLow[] = {"--", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
||||
|
||||
char const* DateTime::DaysStringShortLow[] = {"--", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
|
@@ -27,8 +27,6 @@ namespace Pinetime {
|
||||
December
|
||||
};
|
||||
|
||||
DateTime(System::SystemTask& systemTask);
|
||||
|
||||
void SetTime(uint16_t year,
|
||||
uint8_t month,
|
||||
uint8_t day,
|
||||
@@ -75,8 +73,9 @@ namespace Pinetime {
|
||||
return uptime;
|
||||
}
|
||||
|
||||
void Register(System::SystemTask* systemTask);
|
||||
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
uint16_t year = 0;
|
||||
Months month = Months::Unknown;
|
||||
uint8_t day = 0;
|
||||
@@ -90,6 +89,7 @@ namespace Pinetime {
|
||||
std::chrono::seconds uptime {0};
|
||||
|
||||
bool isMidnightAlreadyNotified = false;
|
||||
System::SystemTask* systemTask = nullptr;
|
||||
|
||||
static char const* DaysString[];
|
||||
static char const* DaysStringShort[];
|
||||
|
197
src/components/fs/FS.cpp
Normal file
197
src/components/fs/FS.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "FS.h"
|
||||
#include <cstring>
|
||||
#include <littlefs/lfs.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
FS::FS(Pinetime::Drivers::SpiNorFlash& driver) :
|
||||
flashDriver{ driver },
|
||||
lfsConfig{
|
||||
.context = this,
|
||||
.read = SectorRead,
|
||||
.prog = SectorProg,
|
||||
.erase = SectorErase,
|
||||
.sync = SectorSync,
|
||||
|
||||
.read_size = 16,
|
||||
.prog_size = 8,
|
||||
.block_size = blockSize,
|
||||
.block_count = size / blockSize,
|
||||
.block_cycles = 1000u,
|
||||
|
||||
.cache_size = 16,
|
||||
.lookahead_size = 16,
|
||||
|
||||
.name_max = 50,
|
||||
.attr_max = 50,
|
||||
}
|
||||
{ }
|
||||
|
||||
|
||||
void FS::Init() {
|
||||
|
||||
// try mount
|
||||
int err = lfs_mount(&lfs, &lfsConfig);
|
||||
|
||||
// reformat if we can't mount the filesystem
|
||||
// this should only happen on the first boot
|
||||
if (err != LFS_ERR_OK) {
|
||||
lfs_format(&lfs, &lfsConfig);
|
||||
err = lfs_mount(&lfs, &lfsConfig);
|
||||
if (err != LFS_ERR_OK) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PINETIME_IS_RECOVERY
|
||||
VerifyResource();
|
||||
LVGLFileSystemInit();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void FS::VerifyResource() {
|
||||
// validate the resource metadata
|
||||
resourcesValid = true;
|
||||
}
|
||||
|
||||
int FS::FileOpen(lfs_file_t* file_p, const char* fileName, const int flags) {
|
||||
return lfs_file_open(&lfs, file_p, fileName, flags);
|
||||
}
|
||||
|
||||
int FS::FileClose(lfs_file_t* file_p) {
|
||||
return lfs_file_close(&lfs, file_p);
|
||||
}
|
||||
|
||||
int FS::FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size) {
|
||||
return lfs_file_read(&lfs, file_p, buff, size);
|
||||
}
|
||||
|
||||
int FS::FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size) {
|
||||
return lfs_file_write(&lfs, file_p, buff, size);
|
||||
}
|
||||
|
||||
int FS::FileSeek(lfs_file_t* file_p, uint32_t pos) {
|
||||
return lfs_file_seek(&lfs, file_p, pos, LFS_SEEK_SET);
|
||||
}
|
||||
|
||||
int FS::FileDelete(const char* fileName) {
|
||||
return lfs_remove(&lfs, fileName);
|
||||
}
|
||||
|
||||
|
||||
int FS::DirCreate(const char* path) {
|
||||
return lfs_mkdir(&lfs, path);
|
||||
}
|
||||
|
||||
// Delete directory and all files inside
|
||||
int FS::DirDelete(const char* path) {
|
||||
|
||||
lfs_dir_t lfs_dir;
|
||||
lfs_info entryInfo;
|
||||
|
||||
int err;
|
||||
err = lfs_dir_open(&lfs, &lfs_dir, path);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
while (lfs_dir_read(&lfs, &lfs_dir, &entryInfo)) {
|
||||
lfs_remove(&lfs, entryInfo.name);
|
||||
}
|
||||
lfs_dir_close(&lfs, &lfs_dir);
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
----------- Interface between littlefs and SpiNorFlash -----------
|
||||
|
||||
*/
|
||||
int FS::SectorSync(const struct lfs_config* c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FS::SectorErase(const struct lfs_config* c, lfs_block_t block) {
|
||||
Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
||||
const size_t address = startAddress + (block * blockSize);
|
||||
lfs.flashDriver.SectorErase(address);
|
||||
return lfs.flashDriver.EraseFailed() ? -1 : 0;
|
||||
}
|
||||
|
||||
int FS::SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) {
|
||||
Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
||||
const size_t address = startAddress + (block * blockSize) + off;
|
||||
lfs.flashDriver.Write(address, (uint8_t*) buffer, size);
|
||||
return lfs.flashDriver.ProgramFailed() ? -1 : 0;
|
||||
}
|
||||
|
||||
int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size) {
|
||||
Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
||||
const size_t address = startAddress + (block * blockSize) + off;
|
||||
lfs.flashDriver.Read(address, static_cast<uint8_t*>(buffer), size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
----------- LVGL filesystem integration -----------
|
||||
|
||||
*/
|
||||
|
||||
namespace {
|
||||
lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) {
|
||||
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
filesys->FileOpen(file, path, LFS_O_RDONLY);
|
||||
|
||||
if (file->type == 0) {
|
||||
return LV_FS_RES_FS_ERR;
|
||||
}
|
||||
else {
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
}
|
||||
|
||||
lv_fs_res_t lvglClose(lv_fs_drv_t* drv, void* file_p) {
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
filesys->FileClose(file);
|
||||
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
|
||||
lv_fs_res_t lvglRead(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) {
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
filesys->FileRead(file, static_cast<uint8_t*>(buf), btr);
|
||||
*br = btr;
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
|
||||
lv_fs_res_t lvglSeek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) {
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
filesys->FileSeek(file, pos);
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void FS::LVGLFileSystemInit() {
|
||||
|
||||
lv_fs_drv_t fs_drv;
|
||||
lv_fs_drv_init(&fs_drv);
|
||||
|
||||
fs_drv.file_size = sizeof(lfs_file_t);
|
||||
fs_drv.letter = 'F';
|
||||
fs_drv.open_cb = lvglOpen;
|
||||
fs_drv.close_cb = lvglClose;
|
||||
fs_drv.read_cb = lvglRead;
|
||||
fs_drv.seek_cb = lvglSeek;
|
||||
|
||||
fs_drv.user_data = this;
|
||||
|
||||
lv_fs_drv_register(&fs_drv);
|
||||
|
||||
}
|
71
src/components/fs/FS.h
Normal file
71
src/components/fs/FS.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "drivers/SpiNorFlash.h"
|
||||
#include <littlefs/lfs.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class FS {
|
||||
public:
|
||||
FS(Pinetime::Drivers::SpiNorFlash&);
|
||||
|
||||
void Init();
|
||||
void LVGLFileSystemInit();
|
||||
|
||||
int FileOpen(lfs_file_t* file_p, const char* fileName, const int flags);
|
||||
int FileClose(lfs_file_t* file_p);
|
||||
int FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size);
|
||||
int FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size);
|
||||
int FileSeek(lfs_file_t* file_p, uint32_t pos);
|
||||
|
||||
int FileDelete(const char* fileName);
|
||||
|
||||
int DirCreate(const char* path);
|
||||
int DirDelete(const char* path);
|
||||
|
||||
void VerifyResource();
|
||||
|
||||
private:
|
||||
|
||||
Pinetime::Drivers::SpiNorFlash& flashDriver;
|
||||
|
||||
/*
|
||||
* External Flash MAP (4 MBytes)
|
||||
*
|
||||
* 0x000000 +---------------------------------------+
|
||||
* | Bootloader Assets |
|
||||
* | 256 KBytes |
|
||||
* | |
|
||||
* 0x040000 +---------------------------------------+
|
||||
* | OTA |
|
||||
* | 464 KBytes |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 0x0B4000 +---------------------------------------+
|
||||
* | File System |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 0x400000 +---------------------------------------+
|
||||
*
|
||||
*/
|
||||
static constexpr size_t startAddress = 0x0B4000;
|
||||
static constexpr size_t size = 0x3C0000;
|
||||
static constexpr size_t blockSize = 4096;
|
||||
|
||||
bool resourcesValid = false;
|
||||
const struct lfs_config lfsConfig;
|
||||
|
||||
lfs_t lfs;
|
||||
|
||||
static int SectorSync(const struct lfs_config* c);
|
||||
static int SectorErase(const struct lfs_config* c, lfs_block_t block);
|
||||
static int SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size);
|
||||
static int SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
@@ -4,9 +4,6 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
HeartRateController::HeartRateController(Pinetime::System::SystemTask& systemTask) : systemTask {systemTask} {
|
||||
}
|
||||
|
||||
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
|
||||
this->state = newState;
|
||||
if (this->heartRate != heartRate) {
|
||||
|
@@ -15,8 +15,7 @@ namespace Pinetime {
|
||||
public:
|
||||
enum class States { Stopped, NotEnoughData, NoTouch, Running };
|
||||
|
||||
explicit HeartRateController(System::SystemTask& systemTask);
|
||||
|
||||
HeartRateController() = default;
|
||||
void Start();
|
||||
void Stop();
|
||||
void Update(States newState, uint8_t heartRate);
|
||||
@@ -32,7 +31,6 @@ namespace Pinetime {
|
||||
void SetService(Pinetime::Controllers::HeartRateService* service);
|
||||
|
||||
private:
|
||||
System::SystemTask& systemTask;
|
||||
Applications::HeartRateTask* task = nullptr;
|
||||
States state = States::Stopped;
|
||||
uint8_t heartRate = 0;
|
||||
|
@@ -38,9 +38,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
Ppg::Ppg(float spl)
|
||||
: offset {spl},
|
||||
hpf {0.87033078, -1.74066156, 0.87033078, -1.72377617, 0.75754694},
|
||||
Ppg::Ppg()
|
||||
: hpf {0.87033078, -1.74066156, 0.87033078, -1.72377617, 0.75754694},
|
||||
agc {20, 0.971, 2},
|
||||
lpf {0.11595249, 0.23190498, 0.11595249, -0.72168143, 0.18549138} {
|
||||
}
|
||||
@@ -67,13 +66,7 @@ float Ppg::HeartRate() {
|
||||
dataIndex = 0;
|
||||
return hr;
|
||||
}
|
||||
|
||||
int cccount = 0;
|
||||
float Ppg::ProcessHeartRate() {
|
||||
|
||||
if (cccount > 2)
|
||||
asm("nop");
|
||||
cccount++;
|
||||
auto t0 = Trough(data.data(), dataIndex, 7, 48);
|
||||
if (t0 < 0)
|
||||
return 0;
|
||||
|
@@ -8,8 +8,7 @@ namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Ppg {
|
||||
public:
|
||||
explicit Ppg(float spl);
|
||||
|
||||
Ppg();
|
||||
int8_t Preprocess(float spl);
|
||||
float HeartRate();
|
||||
|
||||
|
@@ -34,3 +34,10 @@ bool MotionController::ShouldWakeUp(bool isSleeping) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <drivers/Bma421.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class MotionController {
|
||||
public:
|
||||
enum class DeviceTypes{
|
||||
Unknown,
|
||||
BMA421,
|
||||
BMA425,
|
||||
};
|
||||
|
||||
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
|
||||
|
||||
int16_t X() const {
|
||||
@@ -27,6 +34,12 @@ namespace Pinetime {
|
||||
return isSensorOk;
|
||||
}
|
||||
|
||||
DeviceTypes DeviceType() const {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
void Init(Pinetime::Drivers::Bma421::DeviceTypes types);
|
||||
|
||||
private:
|
||||
uint32_t nbSteps;
|
||||
int16_t x;
|
||||
@@ -34,6 +47,7 @@ namespace Pinetime {
|
||||
int16_t z;
|
||||
int16_t lastYForWakeUp = 0;
|
||||
bool isSensorOk = false;
|
||||
DeviceTypes deviceType = DeviceTypes::Unknown;
|
||||
};
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ void MotorController::Init() {
|
||||
nrf_gpio_cfg_output(pinMotor);
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
app_timer_init();
|
||||
|
||||
|
||||
app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, vibrate);
|
||||
app_timer_create(&longVibTimer, APP_TIMER_MODE_REPEATED, vibrate);
|
||||
isBusy = false;
|
||||
@@ -53,4 +53,4 @@ void MotorController::vibrate(void* p_context) {
|
||||
} else {
|
||||
nrf_gpio_pin_clear(pinMotor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ namespace Pinetime {
|
||||
const uint8_t* buffer;
|
||||
size_t size;
|
||||
|
||||
int encodedBufferIndex = 0;
|
||||
size_t encodedBufferIndex = 0;
|
||||
int y = 0;
|
||||
uint16_t bp = 0;
|
||||
uint16_t foregroundColor = 0xffff;
|
||||
|
@@ -4,108 +4,44 @@
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
struct SettingsHeader {
|
||||
uint8_t isActive; // 0xF1 = Block is active, 0xF0 = Block is inactive
|
||||
uint16_t version; // Current version, to verify if the saved data is for the current Version
|
||||
};
|
||||
|
||||
#define HEADER_SIZE sizeof(SettingsHeader)
|
||||
|
||||
Settings::Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} {
|
||||
Settings::Settings(Pinetime::Controllers::FS& fs) : fs {fs} {
|
||||
}
|
||||
|
||||
void Settings::Init() {
|
||||
|
||||
// Load default settings from Flash
|
||||
LoadSettingsFromFlash();
|
||||
LoadSettingsFromFile();
|
||||
}
|
||||
|
||||
void Settings::SaveSettings() {
|
||||
|
||||
// verify if is necessary to save
|
||||
if (settingsChanged) {
|
||||
SaveSettingsToFlash();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
settingsChanged = false;
|
||||
}
|
||||
|
||||
bool Settings::FindHeader() {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
void Settings::LoadSettingsFromFile() {
|
||||
SettingsData bufferSettings;
|
||||
lfs_file_t settingsFile;
|
||||
|
||||
for (uint8_t block = 0; block < 10; block++) {
|
||||
|
||||
spiNorFlash.Read(settingsBaseAddr + (block * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||
std::memcpy(&settingsHeader, bufferHead, sizeof(settingsHeader));
|
||||
if (settingsHeader.isActive == 0xF1 && settingsHeader.version == settingsVersion) {
|
||||
settingsFlashBlock = block;
|
||||
return true;
|
||||
}
|
||||
if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDWR | LFS_O_CREAT) != LFS_ERR_OK) {
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Settings::ReadSettingsData() {
|
||||
uint8_t bufferSettings[sizeof(settings)];
|
||||
spiNorFlash.Read(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||
std::memcpy(&settings, bufferSettings, sizeof(settings));
|
||||
}
|
||||
|
||||
void Settings::EraseBlock() {
|
||||
|
||||
spiNorFlash.SectorErase(settingsBaseAddr + (settingsFlashBlock * 0x1000));
|
||||
}
|
||||
|
||||
void Settings::SetHeader(bool state) {
|
||||
SettingsHeader settingsHeader;
|
||||
uint8_t bufferHead[sizeof(settingsHeader)];
|
||||
settingsHeader.isActive = state ? 0xF1 : 0xF0;
|
||||
settingsHeader.version = settingsVersion;
|
||||
|
||||
std::memcpy(bufferHead, &settingsHeader, sizeof(settingsHeader));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000), bufferHead, sizeof(settingsHeader));
|
||||
}
|
||||
|
||||
void Settings::SaveSettingsData() {
|
||||
uint8_t bufferSettings[sizeof(settings)];
|
||||
std::memcpy(bufferSettings, &settings, sizeof(settings));
|
||||
spiNorFlash.Write(settingsBaseAddr + (settingsFlashBlock * 0x1000) + HEADER_SIZE, bufferSettings, sizeof(settings));
|
||||
}
|
||||
|
||||
void Settings::LoadSettingsFromFlash() {
|
||||
|
||||
if (settingsFlashBlock == 99) {
|
||||
// Find current Block, if can't find use default settings and set block to 0 ans save !
|
||||
if (FindHeader()) {
|
||||
ReadSettingsData();
|
||||
} else {
|
||||
SaveSettingsToFlash();
|
||||
}
|
||||
} else {
|
||||
// Read Settings from flash...
|
||||
// never used :)
|
||||
ReadSettingsData();
|
||||
fs.FileRead(&settingsFile, reinterpret_cast<uint8_t*>(&bufferSettings), sizeof(settings));
|
||||
fs.FileClose(&settingsFile);
|
||||
if ( bufferSettings.version == settingsVersion ) {
|
||||
settings = bufferSettings;
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::SaveSettingsToFlash() {
|
||||
void Settings::SaveSettingsToFile() {
|
||||
lfs_file_t settingsFile;
|
||||
|
||||
// calculate where to save...
|
||||
// mark current to inactive
|
||||
// erase the new location and save
|
||||
// set settingsFlashBlock
|
||||
|
||||
// if first time hever, only saves to block 0 and set settingsFlashBlock
|
||||
|
||||
if (settingsFlashBlock != 99) {
|
||||
SetHeader(false);
|
||||
if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDWR | LFS_O_CREAT) != LFS_ERR_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
settingsFlashBlock++;
|
||||
if (settingsFlashBlock > 9)
|
||||
settingsFlashBlock = 0;
|
||||
|
||||
EraseBlock();
|
||||
SetHeader(true);
|
||||
SaveSettingsData();
|
||||
fs.FileWrite(&settingsFile, reinterpret_cast<uint8_t*>(&settings), sizeof(settings));
|
||||
fs.FileClose(&settingsFile);
|
||||
}
|
||||
|
@@ -1,26 +1,32 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
#include "drivers/SpiNorFlash.h"
|
||||
#include "components/fs/FS.h"
|
||||
#include "drivers/Cst816s.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings {
|
||||
public:
|
||||
enum class ClockType { H24, H12 };
|
||||
enum class Vibration { ON, OFF };
|
||||
enum class WakeUpMode { None, SingleTap, DoubleTap, RaiseWrist };
|
||||
enum class ClockType : uint8_t { H24, H12 };
|
||||
enum class Vibration : uint8_t { ON, OFF };
|
||||
enum class WakeUpMode : uint8_t {
|
||||
SingleTap = 0,
|
||||
DoubleTap = 1,
|
||||
RaiseWrist = 2,
|
||||
};
|
||||
|
||||
Settings(Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||
Settings(Pinetime::Controllers::FS& fs);
|
||||
|
||||
void Init();
|
||||
void SaveSettings();
|
||||
|
||||
void SetClockFace(uint8_t face) {
|
||||
if (face != settings.clockFace)
|
||||
if (face != settings.clockFace) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.clockFace = face;
|
||||
};
|
||||
uint8_t GetClockFace() const {
|
||||
@@ -42,8 +48,9 @@ namespace Pinetime {
|
||||
};
|
||||
|
||||
void SetClockType(ClockType clocktype) {
|
||||
if (clocktype != settings.clockType)
|
||||
if (clocktype != settings.clockType) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.clockType = clocktype;
|
||||
};
|
||||
ClockType GetClockType() const {
|
||||
@@ -51,8 +58,9 @@ namespace Pinetime {
|
||||
};
|
||||
|
||||
void SetVibrationStatus(Vibration status) {
|
||||
if (status != settings.vibrationStatus)
|
||||
if (status != settings.vibrationStatus) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.vibrationStatus = status;
|
||||
};
|
||||
Vibration GetVibrationStatus() const {
|
||||
@@ -60,26 +68,47 @@ namespace Pinetime {
|
||||
};
|
||||
|
||||
void SetScreenTimeOut(uint32_t timeout) {
|
||||
if (timeout != settings.screenTimeOut)
|
||||
if (timeout != settings.screenTimeOut) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.screenTimeOut = timeout;
|
||||
};
|
||||
uint32_t GetScreenTimeOut() const {
|
||||
return settings.screenTimeOut;
|
||||
};
|
||||
|
||||
void setWakeUpMode(WakeUpMode wakeUp) {
|
||||
if (wakeUp != settings.wakeUpMode)
|
||||
void setWakeUpMode(WakeUpMode wakeUp, bool enabled) {
|
||||
if (!isWakeUpModeOn(wakeUp)) {
|
||||
settingsChanged = true;
|
||||
settings.wakeUpMode = wakeUp;
|
||||
};
|
||||
WakeUpMode getWakeUpMode() const {
|
||||
return settings.wakeUpMode;
|
||||
}
|
||||
settings.wakeUpMode.set(static_cast<size_t>(wakeUp), enabled);
|
||||
// Handle special behavior
|
||||
if (enabled) {
|
||||
switch (wakeUp) {
|
||||
case WakeUpMode::SingleTap:
|
||||
settings.wakeUpMode.set(static_cast<size_t>(WakeUpMode::DoubleTap), false);
|
||||
break;
|
||||
case WakeUpMode::DoubleTap:
|
||||
settings.wakeUpMode.set(static_cast<size_t>(WakeUpMode::SingleTap), false);
|
||||
break;
|
||||
case WakeUpMode::RaiseWrist:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::bitset<3> getWakeUpModes() const {
|
||||
return settings.wakeUpMode;
|
||||
}
|
||||
|
||||
bool isWakeUpModeOn(const WakeUpMode mode) const {
|
||||
return getWakeUpModes()[static_cast<size_t>(mode)];
|
||||
}
|
||||
|
||||
void SetBrightness(Controllers::BrightnessController::Levels level) {
|
||||
if (level != settings.brightLevel)
|
||||
if (level != settings.brightLevel) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.brightLevel = level;
|
||||
};
|
||||
Controllers::BrightnessController::Levels GetBrightness() const {
|
||||
@@ -87,26 +116,30 @@ namespace Pinetime {
|
||||
};
|
||||
|
||||
void SetStepsGoal( uint32_t goal ) {
|
||||
if ( goal != settings.stepsGoal )
|
||||
if ( goal != settings.stepsGoal ) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.stepsGoal = goal;
|
||||
};
|
||||
|
||||
uint32_t GetStepsGoal() const { return settings.stepsGoal; };
|
||||
|
||||
private:
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash;
|
||||
Pinetime::Controllers::FS& fs;
|
||||
|
||||
static constexpr uint32_t settingsVersion = 0x0001;
|
||||
struct SettingsData {
|
||||
|
||||
uint32_t version = settingsVersion;
|
||||
uint32_t stepsGoal = 10000;
|
||||
uint32_t screenTimeOut = 15000;
|
||||
|
||||
ClockType clockType = ClockType::H24;
|
||||
Vibration vibrationStatus = Vibration::ON;
|
||||
|
||||
uint8_t clockFace = 0;
|
||||
|
||||
uint32_t stepsGoal = 10000;
|
||||
uint32_t screenTimeOut = 15000;
|
||||
|
||||
WakeUpMode wakeUpMode = WakeUpMode::None;
|
||||
std::bitset<3> wakeUpMode {0};
|
||||
|
||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||
};
|
||||
@@ -117,20 +150,8 @@ namespace Pinetime {
|
||||
uint8_t appMenu = 0;
|
||||
uint8_t settingsMenu = 0;
|
||||
|
||||
// There are 10 blocks of reserved flash to save settings
|
||||
// to minimize wear, the recording is done in a rotating way by the 10 blocks
|
||||
uint8_t settingsFlashBlock = 99; // default to indicate it needs to find the active block
|
||||
|
||||
static constexpr uint32_t settingsBaseAddr = 0x3F6000; // Flash Settings Location
|
||||
static constexpr uint16_t settingsVersion = 0x0100; // Flash Settings Version
|
||||
|
||||
bool FindHeader();
|
||||
void ReadSettingsData();
|
||||
void EraseBlock();
|
||||
void SetHeader(bool state);
|
||||
void SaveSettingsData();
|
||||
void LoadSettingsFromFlash();
|
||||
void SaveSettingsToFlash();
|
||||
void LoadSettingsFromFile();
|
||||
void SaveSettingsToFile();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
src/components/timer/TimerController.cpp
Normal file
69
src/components/timer/TimerController.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Created by florian on 16.05.21.
|
||||
//
|
||||
|
||||
#include "TimerController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "app_timer.h"
|
||||
#include "task.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
||||
APP_TIMER_DEF(timerAppTimer);
|
||||
|
||||
namespace {
|
||||
void TimerEnd(void* p_context) {
|
||||
auto* controller = static_cast<Pinetime::Controllers::TimerController*> (p_context);
|
||||
if(controller != nullptr)
|
||||
controller->OnTimerEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TimerController::Init() {
|
||||
app_timer_create(&timerAppTimer, APP_TIMER_MODE_SINGLE_SHOT, TimerEnd);
|
||||
}
|
||||
|
||||
void TimerController::StartTimer(uint32_t duration) {
|
||||
app_timer_stop(timerAppTimer);
|
||||
auto currentTicks = xTaskGetTickCount();
|
||||
app_timer_start(timerAppTimer, APP_TIMER_TICKS(duration), this);
|
||||
endTicks = currentTicks + APP_TIMER_TICKS(duration);
|
||||
timerRunning = true;
|
||||
}
|
||||
|
||||
uint32_t TimerController::GetTimeRemaining() {
|
||||
if (!timerRunning) {
|
||||
return 0;
|
||||
}
|
||||
auto currentTicks = xTaskGetTickCount();
|
||||
|
||||
TickType_t deltaTicks = 0;
|
||||
if (currentTicks > endTicks) {
|
||||
deltaTicks = 0xffffffff - currentTicks;
|
||||
deltaTicks += (endTicks + 1);
|
||||
} else {
|
||||
deltaTicks = endTicks - currentTicks;
|
||||
}
|
||||
|
||||
return (static_cast<TickType_t>(deltaTicks) / static_cast<TickType_t>(configTICK_RATE_HZ)) * 1000;
|
||||
}
|
||||
|
||||
void TimerController::StopTimer() {
|
||||
app_timer_stop(timerAppTimer);
|
||||
timerRunning = false;
|
||||
}
|
||||
|
||||
bool TimerController::IsRunning() {
|
||||
return timerRunning;
|
||||
}
|
||||
void TimerController::OnTimerEnd() {
|
||||
timerRunning = false;
|
||||
if(systemTask != nullptr)
|
||||
systemTask->PushMessage(System::Messages::OnTimerDone);
|
||||
}
|
||||
|
||||
void TimerController::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
}
|
37
src/components/timer/TimerController.h
Normal file
37
src/components/timer/TimerController.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "app_timer.h"
|
||||
#include "portmacro_cmsis.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
|
||||
class TimerController {
|
||||
public:
|
||||
TimerController() = default;
|
||||
|
||||
void Init();
|
||||
|
||||
void StartTimer(uint32_t duration);
|
||||
|
||||
void StopTimer();
|
||||
|
||||
uint32_t GetTimeRemaining();
|
||||
|
||||
bool IsRunning();
|
||||
|
||||
void OnTimerEnd();
|
||||
|
||||
void Register(System::SystemTask* systemTask);
|
||||
|
||||
private:
|
||||
System::SystemTask* systemTask = nullptr;
|
||||
TickType_t endTicks;
|
||||
bool timerRunning = false;
|
||||
};
|
||||
}
|
||||
}
|
@@ -11,6 +11,7 @@ namespace Pinetime {
|
||||
FirmwareValidation,
|
||||
NotificationsPreview,
|
||||
Notifications,
|
||||
Timer,
|
||||
FlashLight,
|
||||
BatteryInfo,
|
||||
Music,
|
||||
@@ -20,6 +21,7 @@ namespace Pinetime {
|
||||
HeartRate,
|
||||
Navigation,
|
||||
StopWatch,
|
||||
Metronome,
|
||||
Motion,
|
||||
Steps,
|
||||
QuickSettings,
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include <displayapp/screens/HeartRate.h>
|
||||
#include <displayapp/screens/Motion.h>
|
||||
#include <displayapp/screens/Timer.h>
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
@@ -17,6 +18,7 @@
|
||||
#include "displayapp/screens/Paddle.h"
|
||||
#include "displayapp/screens/StopWatch.h"
|
||||
#include "displayapp/screens/Meter.h"
|
||||
#include "displayapp/screens/Metronome.h"
|
||||
#include "displayapp/screens/Music.h"
|
||||
#include "displayapp/screens/Navigation.h"
|
||||
#include "displayapp/screens/Notifications.h"
|
||||
@@ -31,6 +33,7 @@
|
||||
#include "drivers/St7789.h"
|
||||
#include "drivers/Watchdog.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "systemtask/Messages.h"
|
||||
|
||||
#include "displayapp/screens/settings/QuickSettings.h"
|
||||
#include "displayapp/screens/settings/Settings.h"
|
||||
@@ -40,9 +43,42 @@
|
||||
#include "displayapp/screens/settings/SettingDisplay.h"
|
||||
#include "displayapp/screens/settings/SettingSteps.h"
|
||||
|
||||
#include "libs/lv_conf.h"
|
||||
|
||||
using namespace Pinetime::Applications;
|
||||
using namespace Pinetime::Applications::Display;
|
||||
|
||||
namespace {
|
||||
static inline bool in_isr(void) {
|
||||
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
|
||||
}
|
||||
|
||||
TouchEvents Convert(Pinetime::Drivers::Cst816S::TouchInfos info) {
|
||||
if (info.isTouch) {
|
||||
switch (info.gesture) {
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
||||
return TouchEvents::Tap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
||||
return TouchEvents::LongTap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::DoubleTap:
|
||||
return TouchEvents::DoubleTap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideRight:
|
||||
return TouchEvents::SwipeRight;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideLeft:
|
||||
return TouchEvents::SwipeLeft;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideDown:
|
||||
return TouchEvents::SwipeDown;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideUp:
|
||||
return TouchEvents::SwipeUp;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::None:
|
||||
default:
|
||||
return TouchEvents::None;
|
||||
}
|
||||
}
|
||||
return TouchEvents::None;
|
||||
}
|
||||
}
|
||||
|
||||
DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Components::LittleVgl& lvgl,
|
||||
Drivers::Cst816S& touchPanel,
|
||||
@@ -50,12 +86,12 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController)
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController)
|
||||
: lcd {lcd},
|
||||
lvgl {lvgl},
|
||||
touchPanel {touchPanel},
|
||||
@@ -63,18 +99,20 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
bleController {bleController},
|
||||
dateTimeController {dateTimeController},
|
||||
watchdog {watchdog},
|
||||
systemTask {systemTask},
|
||||
notificationManager {notificationManager},
|
||||
heartRateController {heartRateController},
|
||||
settingsController {settingsController},
|
||||
motorController {motorController},
|
||||
motionController {motionController} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
// Start clock when smartwatch boots
|
||||
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||
motionController {motionController},
|
||||
timerController {timerController} {
|
||||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
|
||||
// Start clock when smartwatch boots
|
||||
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None);
|
||||
|
||||
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) {
|
||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
@@ -103,6 +141,7 @@ uint32_t count = 0;
|
||||
bool toggle = true;
|
||||
void DisplayApp::Refresh() {
|
||||
TickType_t queueTimeout;
|
||||
TickType_t delta;
|
||||
switch (state) {
|
||||
case States::Idle:
|
||||
IdleState();
|
||||
@@ -110,7 +149,11 @@ void DisplayApp::Refresh() {
|
||||
break;
|
||||
case States::Running:
|
||||
RunningState();
|
||||
queueTimeout = 20;
|
||||
delta = xTaskGetTickCount() - lastWakeTime;
|
||||
if (delta > LV_DISP_DEF_REFR_PERIOD) {
|
||||
delta = LV_DISP_DEF_REFR_PERIOD;
|
||||
}
|
||||
queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta;
|
||||
break;
|
||||
default:
|
||||
queueTimeout = portMAX_DELAY;
|
||||
@@ -118,16 +161,25 @@ void DisplayApp::Refresh() {
|
||||
}
|
||||
|
||||
Messages msg;
|
||||
if (xQueueReceive(msgQueue, &msg, queueTimeout)) {
|
||||
bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout);
|
||||
lastWakeTime = xTaskGetTickCount();
|
||||
if (messageReceived) {
|
||||
switch (msg) {
|
||||
case Messages::GoToSleep:
|
||||
case Messages::DimScreen:
|
||||
// Backup brightness is the brightness to return to after dimming or sleeping
|
||||
brightnessController.Backup();
|
||||
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
|
||||
break;
|
||||
case Messages::RestoreBrightness:
|
||||
brightnessController.Restore();
|
||||
break;
|
||||
case Messages::GoToSleep:
|
||||
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
|
||||
brightnessController.Lower();
|
||||
vTaskDelay(100);
|
||||
}
|
||||
lcd.DisplayOff();
|
||||
systemTask.PushMessage(System::SystemTask::Messages::OnDisplayTaskSleeping);
|
||||
PushMessageToSystemTask(Pinetime::System::Messages::OnDisplayTaskSleeping);
|
||||
state = States::Idle;
|
||||
break;
|
||||
case Messages::GoToRunning:
|
||||
@@ -136,7 +188,7 @@ void DisplayApp::Refresh() {
|
||||
state = States::Running;
|
||||
break;
|
||||
case Messages::UpdateTimeOut:
|
||||
systemTask.PushMessage(System::SystemTask::Messages::UpdateTimeOut);
|
||||
PushMessageToSystemTask(System::Messages::UpdateTimeOut);
|
||||
break;
|
||||
case Messages::UpdateBleConnection:
|
||||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
|
||||
@@ -148,10 +200,23 @@ void DisplayApp::Refresh() {
|
||||
case Messages::NewNotification:
|
||||
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
case Messages::TimerDone:
|
||||
if (currentApp == Apps::Timer) {
|
||||
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
|
||||
timer->setDone();
|
||||
} else {
|
||||
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
|
||||
}
|
||||
break;
|
||||
case Messages::TouchEvent: {
|
||||
if (state != States::Running)
|
||||
if (state != States::Running) {
|
||||
break;
|
||||
auto gesture = OnTouchEvent();
|
||||
}
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
auto gesture = Convert(info);
|
||||
if (gesture == TouchEvents::None) {
|
||||
break;
|
||||
}
|
||||
if (!currentScreen->OnTouchEvent(gesture)) {
|
||||
if (currentApp == Apps::Clock) {
|
||||
switch (gesture) {
|
||||
@@ -165,22 +230,30 @@ void DisplayApp::Refresh() {
|
||||
LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim);
|
||||
break;
|
||||
case TouchEvents::DoubleTap:
|
||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||
PushMessageToSystemTask(System::Messages::GoToSleep);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (returnTouchEvent == gesture) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
brightnessController.Set(settingsController.GetBrightness());
|
||||
brightnessController.Backup();
|
||||
} else if (touchMode == TouchModes::Gestures) {
|
||||
if (gesture == TouchEvents::Tap) {
|
||||
lvgl.SetNewTapEvent(info.x, info.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Messages::ButtonPushed:
|
||||
if (currentApp == Apps::Clock) {
|
||||
systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
|
||||
PushMessageToSystemTask(System::Messages::GoToSleep);
|
||||
} else {
|
||||
if (!currentScreen->OnButtonPushed()) {
|
||||
LoadApp(returnToApp, returnDirection);
|
||||
brightnessController.Set(settingsController.GetBrightness());
|
||||
brightnessController.Backup();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -195,6 +268,11 @@ void DisplayApp::Refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
if (nextApp != Apps::None) {
|
||||
LoadApp(nextApp, nextDirection);
|
||||
nextApp = Apps::None;
|
||||
}
|
||||
|
||||
if (state != States::Idle && touchMode == TouchModes::Polling) {
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
if (info.action == 2) { // 2 = contact
|
||||
@@ -213,7 +291,8 @@ void DisplayApp::RunningState() {
|
||||
}
|
||||
|
||||
void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) {
|
||||
LoadApp(app, direction);
|
||||
nextApp = app;
|
||||
nextDirection = direction;
|
||||
}
|
||||
|
||||
void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) {
|
||||
@@ -252,18 +331,22 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||
break;
|
||||
case Apps::FirmwareUpdate:
|
||||
currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
|
||||
break;
|
||||
|
||||
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, 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, Screens::Notifications::Modes::Preview);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
|
||||
break;
|
||||
case Apps::Timer:
|
||||
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
|
||||
break;
|
||||
|
||||
// Settings
|
||||
case Apps::QuickSettings:
|
||||
@@ -291,7 +374,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||
currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SettingSteps:
|
||||
case Apps::SettingSteps:
|
||||
currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
@@ -300,18 +383,16 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
case Apps::SysInfo:
|
||||
currentScreen =
|
||||
std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
|
||||
currentScreen = std::make_unique<Screens::SystemInfo>(
|
||||
this, dateTimeController, batteryController, brightnessController, bleController, watchdog, motionController);
|
||||
ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
|
||||
break;
|
||||
//
|
||||
|
||||
case Apps::FlashLight:
|
||||
currentScreen = std::make_unique<Screens::FlashLight>(this, systemTask, brightnessController);
|
||||
currentScreen = std::make_unique<Screens::FlashLight>(this, *systemTask, brightnessController);
|
||||
ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
|
||||
break;
|
||||
case Apps::StopWatch:
|
||||
currentScreen = std::make_unique<Screens::StopWatch>(this);
|
||||
currentScreen = std::make_unique<Screens::StopWatch>(this, *systemTask);
|
||||
break;
|
||||
case Apps::Twos:
|
||||
currentScreen = std::make_unique<Screens::Twos>(this);
|
||||
@@ -323,18 +404,21 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
||||
currentScreen = std::make_unique<Screens::Paddle>(this, lvgl);
|
||||
break;
|
||||
case Apps::Music:
|
||||
currentScreen = std::make_unique<Screens::Music>(this, systemTask.nimble().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());
|
||||
currentScreen = std::make_unique<Screens::Navigation>(this, systemTask->nimble().navigation());
|
||||
break;
|
||||
case Apps::HeartRate:
|
||||
currentScreen = std::make_unique<Screens::HeartRate>(this, heartRateController, systemTask);
|
||||
currentScreen = std::make_unique<Screens::HeartRate>(this, heartRateController, *systemTask);
|
||||
break;
|
||||
case Apps::Metronome:
|
||||
currentScreen = std::make_unique<Screens::Metronome>(this, motorController, *systemTask);
|
||||
break;
|
||||
case Apps::Motion:
|
||||
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
|
||||
break;
|
||||
case Apps::Steps:
|
||||
case Apps::Steps:
|
||||
currentScreen = std::make_unique<Screens::Steps>(this, motionController, settingsController);
|
||||
break;
|
||||
}
|
||||
@@ -345,42 +429,16 @@ void DisplayApp::IdleState() {
|
||||
}
|
||||
|
||||
void DisplayApp::PushMessage(Messages msg) {
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
xHigherPriorityTaskWoken = pdFALSE;
|
||||
xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
/* Actual macro used here is port specific. */
|
||||
// TODO : should I do something here?
|
||||
}
|
||||
}
|
||||
|
||||
TouchEvents DisplayApp::OnTouchEvent() {
|
||||
auto info = touchPanel.GetTouchInfo();
|
||||
if (info.isTouch) {
|
||||
switch (info.gesture) {
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
|
||||
if (touchMode == TouchModes::Gestures) {
|
||||
lvgl.SetNewTapEvent(info.x, info.y);
|
||||
}
|
||||
return TouchEvents::Tap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::LongPress:
|
||||
return TouchEvents::LongTap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::DoubleTap:
|
||||
return TouchEvents::DoubleTap;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideRight:
|
||||
return TouchEvents::SwipeRight;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideLeft:
|
||||
return TouchEvents::SwipeLeft;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideDown:
|
||||
return TouchEvents::SwipeDown;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::SlideUp:
|
||||
return TouchEvents::SwipeUp;
|
||||
case Pinetime::Drivers::Cst816S::Gestures::None:
|
||||
default:
|
||||
return TouchEvents::None;
|
||||
if (in_isr()) {
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
xHigherPriorityTaskWoken = pdFALSE;
|
||||
xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
} else {
|
||||
xQueueSend(msgQueue, &msg, portMAX_DELAY);
|
||||
}
|
||||
return TouchEvents::None;
|
||||
}
|
||||
|
||||
void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||
@@ -411,3 +469,12 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
||||
void DisplayApp::SetTouchMode(DisplayApp::TouchModes mode) {
|
||||
touchMode = mode;
|
||||
}
|
||||
|
||||
void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) {
|
||||
if (systemTask != nullptr)
|
||||
systemTask->PushMessage(message);
|
||||
}
|
||||
|
||||
void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <queue.h>
|
||||
#include <task.h>
|
||||
#include <memory>
|
||||
#include <systemtask/Messages.h>
|
||||
#include "Apps.h"
|
||||
#include "LittleVgl.h"
|
||||
#include "TouchEvents.h"
|
||||
@@ -12,6 +13,7 @@
|
||||
#include "components/firmwarevalidator/FirmwareValidator.h"
|
||||
#include "components/settings/Settings.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "components/timer/TimerController.h"
|
||||
#include "Messages.h"
|
||||
|
||||
namespace Pinetime {
|
||||
@@ -48,12 +50,12 @@ namespace Pinetime {
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController);
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController);
|
||||
void Start();
|
||||
void PushMessage(Display::Messages msg);
|
||||
|
||||
@@ -62,6 +64,8 @@ namespace Pinetime {
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
void SetTouchMode(TouchModes mode);
|
||||
|
||||
void Register(Pinetime::System::SystemTask* systemTask);
|
||||
|
||||
private:
|
||||
Pinetime::Drivers::St7789& lcd;
|
||||
Pinetime::Components::LittleVgl& lvgl;
|
||||
@@ -70,12 +74,13 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
Pinetime::Drivers::WatchdogView& watchdog;
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::System::SystemTask* systemTask = nullptr;
|
||||
Pinetime::Controllers::NotificationManager& notificationManager;
|
||||
Pinetime::Controllers::HeartRateController& heartRateController;
|
||||
Pinetime::Controllers::Settings& settingsController;
|
||||
Pinetime::Controllers::MotorController& motorController;
|
||||
Pinetime::Controllers::MotionController& motionController;
|
||||
Pinetime::Controllers::TimerController& timerController;
|
||||
|
||||
Pinetime::Controllers::FirmwareValidator validator;
|
||||
Controllers::BrightnessController brightnessController;
|
||||
@@ -97,7 +102,6 @@ namespace Pinetime {
|
||||
|
||||
TouchModes touchMode = TouchModes::Gestures;
|
||||
|
||||
TouchEvents OnTouchEvent();
|
||||
void RunningState();
|
||||
void IdleState();
|
||||
static void Process(void* instance);
|
||||
@@ -105,6 +109,11 @@ namespace Pinetime {
|
||||
void Refresh();
|
||||
void ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent);
|
||||
void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction);
|
||||
void PushMessageToSystemTask(Pinetime::System::Messages message);
|
||||
|
||||
Apps nextApp = Apps::None;
|
||||
DisplayApp::FullRefreshDirections nextDirection;
|
||||
TickType_t lastWakeTime;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -14,17 +14,18 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController)
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController)
|
||||
: lcd {lcd}, bleController {bleController} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
|
||||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 512, this, 0, &taskHandle))
|
||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
@@ -112,4 +113,8 @@ void DisplayApp::PushMessage(Display::Messages msg) {
|
||||
/* Actual macro used here is port specific. */
|
||||
// TODO : should I do something here?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "Apps.h"
|
||||
#include "Messages.h"
|
||||
#include "DummyLittleVgl.h"
|
||||
#include "components/timer/TimerController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
@@ -38,14 +39,15 @@ namespace Pinetime {
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Drivers::WatchdogView& watchdog,
|
||||
System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::HeartRateController& heartRateController,
|
||||
Pinetime::Controllers::Settings& settingsController,
|
||||
Controllers::Settings& settingsController,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController);
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController);
|
||||
void Start();
|
||||
void PushMessage(Pinetime::Applications::Display::Messages msg);
|
||||
void Register(Pinetime::System::SystemTask* systemTask);
|
||||
|
||||
private:
|
||||
TaskHandle_t taskHandle;
|
||||
|
@@ -19,6 +19,10 @@ namespace Pinetime {
|
||||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
|
||||
void Init() {
|
||||
|
||||
}
|
||||
|
||||
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
||||
}
|
||||
bool GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||
|
@@ -23,6 +23,10 @@ bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
|
||||
|
||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
|
||||
: lcd {lcd}, touchPanel {touchPanel}, previousClick {0, 0} {
|
||||
|
||||
}
|
||||
|
||||
void LittleVgl::Init() {
|
||||
lv_init();
|
||||
InitTheme();
|
||||
InitDisplay();
|
||||
|
@@ -19,6 +19,8 @@ namespace Pinetime {
|
||||
LittleVgl(LittleVgl&&) = delete;
|
||||
LittleVgl& operator=(LittleVgl&&) = delete;
|
||||
|
||||
void Init();
|
||||
|
||||
void FlushDisplay(const lv_area_t* area, lv_color_t* color_p);
|
||||
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
||||
void SetFullRefresh(FullRefreshDirections direction);
|
||||
|
@@ -11,9 +11,12 @@ namespace Pinetime {
|
||||
TouchEvent,
|
||||
ButtonPushed,
|
||||
NewNotification,
|
||||
TimerDone,
|
||||
BleFirmwareUpdateStarted,
|
||||
UpdateTimeOut
|
||||
UpdateTimeOut,
|
||||
DimScreen,
|
||||
RestoreBrightness
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
src/displayapp/fonts/JetBrainsMono-Bold.ttf
Normal file
BIN
src/displayapp/fonts/JetBrainsMono-Bold.ttf
Normal file
Binary file not shown.
@@ -2,6 +2,7 @@
|
||||
|
||||
* [Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)
|
||||
* [Awesome font from LVGL](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff)
|
||||
* [Open Sans Light from Google](https://fonts.google.com/specimen/Open+Sans)
|
||||
|
||||
## Generate the fonts:
|
||||
|
||||
@@ -10,10 +11,12 @@
|
||||
* Size : 20
|
||||
* Bpp : 1 bit-per-pixel
|
||||
* Do not enable font compression and horizontal subpixel hinting
|
||||
* Load the file `JetBrainsMono-Bold.tff` and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
||||
* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7f, 0x410-0x44f`
|
||||
* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following
|
||||
range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024`
|
||||
range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015`
|
||||
* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts`
|
||||
* Add the font .c file path to src/CMakeLists.txt
|
||||
* Add an LV_FONT_DECLARE line in src/libs/lv_conf.h
|
||||
|
||||
Add new symbols:
|
||||
|
||||
@@ -28,6 +31,21 @@ Add new symbols:
|
||||
static constexpr const char* newSymbol = "\xEF\x86\x85";
|
||||
```
|
||||
|
||||
## Simple method to generate a font
|
||||
|
||||
If you want to generate a basic font containing only numbers and letters, you can use the above settings but instead of specifying a range, simply list the characters you need in the Symbols field and leave the range blank. This is the approach used for the PineTimeStyle watchface.
|
||||
This works well for fonts which will only be used to display numbers, but will fail if you try to add a colon or other punctuation.
|
||||
|
||||
* Open the [LVGL font converter](https://lvgl.io/tools/fontconverter)
|
||||
* Name : open_sans_light
|
||||
* Size : 150
|
||||
* Bpp : 1 bit-per-pixel
|
||||
* Do not enable font compression and horizontal subpixel hinting
|
||||
* Load the file `open_sans_light.tff` (use the file in this repo to ensure the version matches) and specify the following symbols : `0123456789`
|
||||
* Click on Convert, and download the file `open_sans_light.c` and copy it in `src/DisplayApp/Fonts`
|
||||
* Add the font .c file path to src/CMakeLists.txt (search for jetbrains to find the appropriate location/format)
|
||||
* Add an LV_FONT_DECLARE line in src/libs/lv_conf.h (as above)
|
||||
|
||||
#### Navigation font
|
||||
|
||||
To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app)
|
||||
|
File diff suppressed because it is too large
Load Diff
1261
src/displayapp/fonts/open_sans_light.c
Normal file
1261
src/displayapp/fonts/open_sans_light.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/displayapp/fonts/open_sans_light.ttf
Normal file
BIN
src/displayapp/fonts/open_sans_light.ttf
Normal file
Binary file not shown.
@@ -48,6 +48,7 @@ static lv_style_t style_sw_bg;
|
||||
static lv_style_t style_sw_indic;
|
||||
static lv_style_t style_sw_knob;
|
||||
static lv_style_t style_arc_bg;
|
||||
static lv_style_t style_arc_knob;
|
||||
static lv_style_t style_arc_indic;
|
||||
static lv_style_t style_table_cell;
|
||||
static lv_style_t style_pad_small;
|
||||
@@ -191,6 +192,7 @@ static void basic_init(void) {
|
||||
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
|
||||
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
|
||||
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_bg_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
|
||||
style_init_reset(&style_ddlist_selected);
|
||||
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
@@ -239,6 +241,13 @@ static void basic_init(void) {
|
||||
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25));
|
||||
lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true);
|
||||
lv_style_set_pad_all(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(5));
|
||||
|
||||
lv_style_reset(&style_arc_knob);
|
||||
lv_style_set_radius(&style_arc_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_style_set_bg_opa(&style_arc_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
|
||||
lv_style_set_bg_color(&style_arc_knob, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY);
|
||||
lv_style_set_pad_all(&style_arc_knob, LV_STATE_DEFAULT, LV_DPX(5));
|
||||
|
||||
style_init_reset(&style_table_cell);
|
||||
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
|
||||
@@ -447,6 +456,10 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_INDIC);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_INDIC);
|
||||
_lv_style_list_add_style(list, &style_arc_indic);
|
||||
|
||||
lv_obj_clean_style_list(obj, LV_ARC_PART_KNOB);
|
||||
list = lv_obj_get_style_list(obj, LV_ARC_PART_KNOB);
|
||||
_lv_style_list_add_style(list, &style_arc_knob);
|
||||
break;
|
||||
|
||||
case LV_THEME_SWITCH:
|
||||
|
@@ -51,7 +51,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
||||
{Symbols::map, Apps::Navigation},
|
||||
{Symbols::shoe, Apps::Steps},
|
||||
{Symbols::heartBeat, Apps::HeartRate},
|
||||
{"", Apps::None},
|
||||
{Symbols::hourGlass, Apps::Timer},
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||
@@ -62,8 +62,8 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
{Symbols::paintbrush, Apps::Paint},
|
||||
{Symbols::paddle, Apps::Paddle},
|
||||
{"2", Apps::Twos},
|
||||
{"M", Apps::Motion},
|
||||
{"", Apps::None},
|
||||
{Symbols::chartLine, Apps::Motion},
|
||||
{Symbols::drum, Apps::Metronome},
|
||||
{"", Apps::None},
|
||||
}};
|
||||
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#include <cstdint>
|
||||
#include "BatteryIcon.h"
|
||||
#include "Symbols.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
const char* BatteryIcon::GetBatteryIcon(int batteryPercent) {
|
||||
const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) {
|
||||
if (batteryPercent > 90)
|
||||
return Symbols::batteryFull;
|
||||
if (batteryPercent > 75)
|
||||
|
@@ -6,7 +6,7 @@ namespace Pinetime {
|
||||
class BatteryIcon {
|
||||
public:
|
||||
static const char* GetUnknownIcon();
|
||||
static const char* GetBatteryIcon(int batteryPercent);
|
||||
static const char* GetBatteryIcon(uint8_t batteryPercent);
|
||||
static const char* GetPlugIcon(bool isCharging);
|
||||
};
|
||||
}
|
||||
|
@@ -9,11 +9,6 @@ static void lv_update_task(struct _lv_task_t* task) {
|
||||
user_data->UpdateScreen();
|
||||
}
|
||||
|
||||
static void lv_anim_task(struct _lv_task_t* task) {
|
||||
auto user_data = static_cast<BatteryInfo*>(task->user_data);
|
||||
user_data->UpdateAnim();
|
||||
}
|
||||
|
||||
BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController)
|
||||
: Screen(app), batteryController {batteryController} {
|
||||
|
||||
@@ -24,12 +19,12 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
|
||||
lv_obj_set_size(charging_bar, 200, 15);
|
||||
lv_bar_set_range(charging_bar, 0, 100);
|
||||
lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
|
||||
lv_bar_set_anim_time(charging_bar, 2000);
|
||||
lv_bar_set_anim_time(charging_bar, 1000);
|
||||
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
||||
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
|
||||
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF);
|
||||
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
|
||||
|
||||
status = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_static(status, "Reading Battery status");
|
||||
@@ -38,24 +33,13 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
|
||||
|
||||
percent = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||
if (batteryPercent >= 0) {
|
||||
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||
} else {
|
||||
lv_label_set_text(percent, "--%");
|
||||
}
|
||||
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
|
||||
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
|
||||
|
||||
// hack to not use the flot functions from printf
|
||||
uint8_t batteryVoltageBytes[2];
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||
batteryVoltageBytes[0] =
|
||||
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||
//
|
||||
|
||||
voltage = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC6A600));
|
||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
|
||||
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
|
||||
|
||||
@@ -65,40 +49,15 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text_static(backgroundLabel, "");
|
||||
|
||||
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_LOW, this);
|
||||
taskAnim = lv_task_create(lv_anim_task, 1000, LV_TASK_PRIO_LOW, this);
|
||||
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this);
|
||||
UpdateScreen();
|
||||
}
|
||||
|
||||
BatteryInfo::~BatteryInfo() {
|
||||
lv_task_del(taskUpdate);
|
||||
lv_task_del(taskAnim);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void BatteryInfo::UpdateAnim() {
|
||||
batteryPercent = batteryController.PercentRemaining();
|
||||
|
||||
if (batteryPercent >= 0) {
|
||||
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||
animation += 1;
|
||||
if (animation >= 100) {
|
||||
animation = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (animation > batteryPercent) {
|
||||
animation--;
|
||||
}
|
||||
if (animation < batteryPercent) {
|
||||
animation++;
|
||||
}
|
||||
}
|
||||
|
||||
lv_bar_set_value(charging_bar, animation, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void BatteryInfo::UpdateScreen() {
|
||||
|
||||
batteryController.Update();
|
||||
@@ -106,39 +65,27 @@ void BatteryInfo::UpdateScreen() {
|
||||
batteryPercent = batteryController.PercentRemaining();
|
||||
batteryVoltage = batteryController.Voltage();
|
||||
|
||||
if (batteryPercent >= 0) {
|
||||
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_label_set_text_static(status, "Battery charging");
|
||||
} else if (batteryPercent == 100) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
|
||||
lv_label_set_text_static(status, "Battery is fully charged");
|
||||
} else if (batteryPercent < 10) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
lv_label_set_text_static(status, "Battery is low");
|
||||
} else {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_label_set_text_static(status, "Battery discharging");
|
||||
}
|
||||
|
||||
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||
|
||||
if (batteryController.IsCharging() and batteryPercent < 100) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_label_set_text_static(status, "Charging");
|
||||
} else if (batteryPercent == 100) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
|
||||
lv_label_set_text_static(status, "Fully charged");
|
||||
} else if (batteryPercent < 10) {
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
lv_label_set_text_static(status, "Battery low");
|
||||
} else {
|
||||
lv_label_set_text_static(status, "Reading Battery status");
|
||||
lv_label_set_text(percent, "--%");
|
||||
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_label_set_text_static(status, "Discharging");
|
||||
}
|
||||
|
||||
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
|
||||
|
||||
lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
|
||||
// hack to not use the flot functions from printf
|
||||
uint8_t batteryVoltageBytes[2];
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||
batteryVoltageBytes[0] =
|
||||
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||
//
|
||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltageBytes[1], batteryVoltageBytes[0]);
|
||||
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
|
||||
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
|
||||
}
|
||||
|
||||
bool BatteryInfo::Refresh() {
|
||||
|
||||
return running;
|
||||
}
|
||||
|
@@ -22,7 +22,6 @@ namespace Pinetime {
|
||||
bool Refresh() override;
|
||||
|
||||
void UpdateScreen();
|
||||
void UpdateAnim();
|
||||
|
||||
private:
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
@@ -33,11 +32,9 @@ namespace Pinetime {
|
||||
lv_obj_t* status;
|
||||
|
||||
lv_task_t* taskUpdate;
|
||||
lv_task_t* taskAnim;
|
||||
|
||||
int8_t animation = 0;
|
||||
int8_t batteryPercent = -1;
|
||||
float batteryVoltage = 0.0f;
|
||||
uint8_t batteryPercent = 0;
|
||||
uint16_t batteryVoltage = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "../DisplayApp.h"
|
||||
#include "WatchFaceDigital.h"
|
||||
#include "WatchFaceAnalog.h"
|
||||
#include "PineTimeStyle.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
@@ -33,21 +34,20 @@ Clock::Clock(DisplayApp* app,
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController},
|
||||
screens {app,
|
||||
settingsController.GetClockFace(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return WatchFaceDigitalScreen();
|
||||
},
|
||||
[this]() -> std::unique_ptr<Screen> {
|
||||
return WatchFaceAnalogScreen();
|
||||
},
|
||||
// Examples for more watch faces
|
||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); },
|
||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); }
|
||||
},
|
||||
Screens::ScreenListModes::LongPress} {
|
||||
|
||||
screen {[this, &settingsController]() {
|
||||
switch (settingsController.GetClockFace()) {
|
||||
case 0:
|
||||
return WatchFaceDigitalScreen();
|
||||
break;
|
||||
case 1:
|
||||
return WatchFaceAnalogScreen();
|
||||
break;
|
||||
case 2:
|
||||
return PineTimeStyleScreen();
|
||||
break;
|
||||
}
|
||||
return WatchFaceDigitalScreen();
|
||||
}()} {
|
||||
settingsController.SetAppMenu(0);
|
||||
}
|
||||
|
||||
@@ -56,12 +56,12 @@ Clock::~Clock() {
|
||||
}
|
||||
|
||||
bool Clock::Refresh() {
|
||||
screens.Refresh();
|
||||
screen->Refresh();
|
||||
return running;
|
||||
}
|
||||
|
||||
bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return screens.OnTouchEvent(event);
|
||||
return screen->OnTouchEvent(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
||||
@@ -80,6 +80,16 @@ std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||
app, dateTimeController, batteryController, bleController, notificatioManager, settingsController);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::PineTimeStyleScreen() {
|
||||
return std::make_unique<Screens::PineTimeStyle>(app,
|
||||
dateTimeController,
|
||||
batteryController,
|
||||
bleController,
|
||||
notificatioManager,
|
||||
settingsController,
|
||||
motionController);
|
||||
}
|
||||
|
||||
/*
|
||||
// Examples for more watch faces
|
||||
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
|
||||
|
@@ -4,8 +4,8 @@
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <components/heartrate/HeartRateController.h>
|
||||
#include "Screen.h"
|
||||
#include "ScreenList.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
@@ -47,9 +47,10 @@ namespace Pinetime {
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
|
||||
ScreenList<2> screens;
|
||||
std::unique_ptr<Screen> screen;
|
||||
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
||||
std::unique_ptr<Screen> WatchFaceAnalogScreen();
|
||||
std::unique_ptr<Screen> PineTimeStyleScreen();
|
||||
|
||||
// Examples for more watch faces
|
||||
// std::unique_ptr<Screen> WatchFaceMinimalScreen();
|
||||
|
@@ -27,9 +27,10 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime
|
||||
lv_bar_set_value(bar1, 0, LV_ANIM_OFF);
|
||||
|
||||
percentLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(percentLabel, "");
|
||||
lv_label_set_text(percentLabel, "Waiting...");
|
||||
lv_obj_set_auto_realign(percentLabel, true);
|
||||
lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60);
|
||||
startTime = xTaskGetTickCount();
|
||||
}
|
||||
|
||||
FirmwareUpdate::~FirmwareUpdate() {
|
||||
@@ -40,26 +41,42 @@ bool FirmwareUpdate::Refresh() {
|
||||
switch (bleController.State()) {
|
||||
default:
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
|
||||
// This condition makes sure that the app is exited if somehow it got
|
||||
// launched without a firmware update. This should never happen.
|
||||
if (state != States::Error) {
|
||||
if (xTaskGetTickCount() - startTime > (60 * 1024)) {
|
||||
UpdateError();
|
||||
state = States::Error;
|
||||
}
|
||||
} else if (xTaskGetTickCount() - startTime > (5 * 1024)) {
|
||||
running = false;
|
||||
}
|
||||
break;
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
|
||||
if (state != States::Running)
|
||||
state = States::Running;
|
||||
return DisplayProgression();
|
||||
DisplayProgression();
|
||||
break;
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
|
||||
if (state != States::Validated) {
|
||||
UpdateValidated();
|
||||
state = States::Validated;
|
||||
}
|
||||
return running;
|
||||
break;
|
||||
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
|
||||
if (state != States::Error) {
|
||||
UpdateError();
|
||||
state = States::Error;
|
||||
}
|
||||
return running;
|
||||
if (xTaskGetTickCount() - startTime > (5 * 1024)) {
|
||||
running = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
bool FirmwareUpdate::DisplayProgression() const {
|
||||
void FirmwareUpdate::DisplayProgression() const {
|
||||
float current = bleController.FirmwareUpdateCurrentBytes() / 1024.0f;
|
||||
float total = bleController.FirmwareUpdateTotalBytes() / 1024.0f;
|
||||
int16_t pc = (current / total) * 100.0f;
|
||||
@@ -67,7 +84,6 @@ bool FirmwareUpdate::DisplayProgression() const {
|
||||
lv_label_set_text(percentLabel, percentStr);
|
||||
|
||||
lv_bar_set_value(bar1, pc, LV_ANIM_OFF);
|
||||
return running;
|
||||
}
|
||||
|
||||
void FirmwareUpdate::UpdateValidated() {
|
||||
@@ -78,4 +94,9 @@ void FirmwareUpdate::UpdateValidated() {
|
||||
void FirmwareUpdate::UpdateError() {
|
||||
lv_label_set_recolor(percentLabel, true);
|
||||
lv_label_set_text(percentLabel, "#ff0000 Error!#");
|
||||
startTime = xTaskGetTickCount();
|
||||
}
|
||||
|
||||
bool FirmwareUpdate::OnButtonPushed() {
|
||||
return true;
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Screen.h"
|
||||
#include <lvgl/src/lv_core/lv_obj.h>
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
@@ -25,13 +26,17 @@ namespace Pinetime {
|
||||
lv_obj_t* titleLabel;
|
||||
mutable char percentStr[10];
|
||||
|
||||
States state;
|
||||
States state = States::Idle;
|
||||
|
||||
bool DisplayProgression() const;
|
||||
void DisplayProgression() const;
|
||||
|
||||
bool OnButtonPushed() override;
|
||||
|
||||
void UpdateValidated();
|
||||
|
||||
void UpdateError();
|
||||
|
||||
TickType_t startTime;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -16,19 +16,18 @@ namespace {
|
||||
|
||||
FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator)
|
||||
: Screen {app}, validator {validator} {
|
||||
labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
lv_label_set_text(labelVersionInfo, "Version : ");
|
||||
lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
|
||||
|
||||
labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
lv_label_set_recolor(labelVersionValue, true);
|
||||
sprintf(version, "%ld.%ld.%ld", Version::Major(), Version::Minor(), Version::Patch());
|
||||
lv_label_set_text(labelVersionValue, version);
|
||||
labelVersion = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_fmt(labelVersion,
|
||||
"Version : %d.%d.%d\n"
|
||||
"ShortRef : %s",
|
||||
Version::Major(),
|
||||
Version::Minor(),
|
||||
Version::Patch(),
|
||||
Version::GitCommitHash());
|
||||
lv_obj_align(labelVersion, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
|
||||
labelIsValidated = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(labelIsValidated, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 50);
|
||||
lv_obj_align(labelIsValidated, labelVersion, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
|
||||
lv_label_set_recolor(labelIsValidated, true);
|
||||
lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
|
||||
lv_obj_set_width(labelIsValidated, 240);
|
||||
|
@@ -23,9 +23,7 @@ namespace Pinetime {
|
||||
private:
|
||||
Pinetime::Controllers::FirmwareValidator& validator;
|
||||
|
||||
lv_obj_t* labelVersionInfo;
|
||||
lv_obj_t* labelVersionValue;
|
||||
char version[9];
|
||||
lv_obj_t* labelVersion;
|
||||
lv_obj_t* labelIsValidated;
|
||||
lv_obj_t* buttonValidate;
|
||||
lv_obj_t* labelButtonValidate;
|
||||
|
@@ -39,14 +39,14 @@ FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
|
||||
backgroundAction->user_data = this;
|
||||
lv_obj_set_event_cb(backgroundAction, event_handler);
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
}
|
||||
|
||||
FlashLight::~FlashLight() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
brightness.Restore();
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
}
|
||||
|
||||
void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
@@ -70,5 +70,5 @@ bool FlashLight::Refresh() {
|
||||
}
|
||||
|
||||
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@@ -63,12 +63,12 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
|
||||
label_startStop = lv_label_create(btn_startStop, nullptr);
|
||||
UpdateStartStopButton(isHrRunning);
|
||||
if (isHrRunning)
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
}
|
||||
|
||||
HeartRate::~HeartRate() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
}
|
||||
|
||||
bool HeartRate::Refresh() {
|
||||
@@ -95,12 +95,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
|
||||
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
|
||||
heartRateController.Start();
|
||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::DisableSleeping);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
} else {
|
||||
heartRateController.Stop();
|
||||
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::EnableSleeping);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
}
|
||||
}
|
||||
|
@@ -15,8 +15,6 @@ namespace Pinetime {
|
||||
bool Refresh() override;
|
||||
|
||||
private:
|
||||
bool running = true;
|
||||
|
||||
lv_obj_t* labelText = nullptr;
|
||||
lv_point_t pageIndicatorBasePoints[2];
|
||||
lv_point_t pageIndicatorPoints[2];
|
||||
@@ -25,4 +23,4 @@ namespace Pinetime {
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
169
src/displayapp/screens/Metronome.cpp
Normal file
169
src/displayapp/screens/Metronome.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include "Metronome.h"
|
||||
|
||||
#include "Screen.h"
|
||||
#include "Symbols.h"
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "FreeRTOSConfig.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
float 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 static_cast<float>(delta) / static_cast<float>(configTICK_RATE_HZ);
|
||||
}
|
||||
|
||||
static void eventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
Metronome* screen = static_cast<Metronome*>(obj->user_data);
|
||||
screen->OnEvent(obj, event);
|
||||
}
|
||||
|
||||
lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x = 0, uint8_t y = 0) {
|
||||
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
|
||||
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
lv_label_set_text(label, name);
|
||||
lv_obj_align(label, reference, align, x, y);
|
||||
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask)
|
||||
: Screen(app), running {true}, currentState {States::Stopped}, startTime {}, motorController {motorController}, systemTask {systemTask} {
|
||||
|
||||
bpmArc = lv_arc_create(lv_scr_act(), nullptr);
|
||||
bpmArc->user_data = this;
|
||||
lv_obj_set_event_cb(bpmArc, eventHandler);
|
||||
lv_arc_set_bg_angles(bpmArc, 0, 270);
|
||||
lv_arc_set_rotation(bpmArc, 135);
|
||||
lv_arc_set_range(bpmArc, 40, 220);
|
||||
lv_arc_set_value(bpmArc, bpm);
|
||||
lv_obj_set_size(bpmArc, 210, 210);
|
||||
lv_arc_set_adjustable(bpmArc, true);
|
||||
lv_obj_align(bpmArc, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 7);
|
||||
|
||||
bpmValue = createLabel(std::to_string(lv_arc_get_value(bpmArc)).c_str(), bpmArc, LV_ALIGN_IN_TOP_MID, &jetbrains_mono_76, 0, 55);
|
||||
bpmLegend = createLabel("bpm", bpmValue, LV_ALIGN_OUT_BOTTOM_MID, &jetbrains_mono_bold_20, 0, 0);
|
||||
|
||||
bpmTap = lv_btn_create(lv_scr_act(), nullptr);
|
||||
bpmTap->user_data = this;
|
||||
lv_obj_set_event_cb(bpmTap, eventHandler);
|
||||
lv_obj_set_style_local_bg_opa(bpmTap, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
|
||||
lv_obj_set_height(bpmTap, 80);
|
||||
lv_obj_align(bpmTap, bpmValue, LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||
|
||||
bpbDropdown = lv_dropdown_create(lv_scr_act(), nullptr);
|
||||
bpbDropdown->user_data = this;
|
||||
lv_obj_set_event_cb(bpbDropdown, eventHandler);
|
||||
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_MAIN, LV_STATE_DEFAULT, 20);
|
||||
lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_LIST, LV_STATE_DEFAULT, 20);
|
||||
lv_obj_align(bpbDropdown, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 15, -4);
|
||||
lv_dropdown_set_options(bpbDropdown, "1\n2\n3\n4\n5\n6\n7\n8\n9");
|
||||
lv_dropdown_set_selected(bpbDropdown, bpb - 1);
|
||||
bpbLegend = lv_label_create(bpbDropdown, nullptr);
|
||||
lv_label_set_text(bpbLegend, "bpb");
|
||||
lv_obj_align(bpbLegend, bpbDropdown, LV_ALIGN_IN_RIGHT_MID, -15, 0);
|
||||
|
||||
playPause = lv_btn_create(lv_scr_act(), nullptr);
|
||||
playPause->user_data = this;
|
||||
lv_obj_set_event_cb(playPause, eventHandler);
|
||||
lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10);
|
||||
lv_obj_set_height(playPause, 39);
|
||||
playPauseLabel = lv_label_create(playPause, nullptr);
|
||||
lv_label_set_text(playPauseLabel, Symbols::play);
|
||||
|
||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
||||
}
|
||||
|
||||
Metronome::~Metronome() {
|
||||
app->SetTouchMode(DisplayApp::TouchModes::Gestures);
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool Metronome::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Metronome::Refresh() {
|
||||
switch (currentState) {
|
||||
case States::Stopped: {
|
||||
break;
|
||||
}
|
||||
case States::Running: {
|
||||
if (calculateDelta(startTime, xTaskGetTickCount()) >= (60.0 / bpm)) {
|
||||
counter--;
|
||||
startTime -= 60.0 / bpm;
|
||||
startTime = xTaskGetTickCount();
|
||||
if (counter == 0) {
|
||||
counter = bpb;
|
||||
motorController.SetDuration(90);
|
||||
} else {
|
||||
motorController.SetDuration(30);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
switch (event) {
|
||||
case LV_EVENT_VALUE_CHANGED: {
|
||||
if (obj == bpmArc) {
|
||||
bpm = lv_arc_get_value(bpmArc);
|
||||
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
|
||||
} else if (obj == bpbDropdown) {
|
||||
bpb = lv_dropdown_get_selected(obj) + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_EVENT_PRESSED: {
|
||||
if (obj == bpmTap) {
|
||||
float timeDelta = calculateDelta(tappedTime, xTaskGetTickCount());
|
||||
if (tappedTime == 0 || timeDelta > 3) {
|
||||
tappedTime = xTaskGetTickCount();
|
||||
} else {
|
||||
bpm = ceil(60.0 / timeDelta);
|
||||
lv_arc_set_value(bpmArc, bpm);
|
||||
lv_label_set_text_fmt(bpmValue, "%03d", bpm);
|
||||
tappedTime = xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_EVENT_CLICKED: {
|
||||
if (obj == playPause) {
|
||||
currentState = (currentState == States::Stopped ? States::Running : States::Stopped);
|
||||
switch (currentState) {
|
||||
case States::Stopped: {
|
||||
lv_label_set_text(playPauseLabel, Symbols::play);
|
||||
systemTask.PushMessage(System::Messages::EnableSleeping);
|
||||
break;
|
||||
}
|
||||
case States::Running: {
|
||||
lv_label_set_text(playPauseLabel, Symbols::pause);
|
||||
systemTask.PushMessage(System::Messages::DisableSleeping);
|
||||
startTime = xTaskGetTickCount();
|
||||
counter = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
34
src/displayapp/screens/Metronome.h
Normal file
34
src/displayapp/screens/Metronome.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "components/motor/MotorController.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Pinetime::Applications::Screens {
|
||||
|
||||
class Metronome : public Screen {
|
||||
public:
|
||||
Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask);
|
||||
~Metronome() override;
|
||||
bool Refresh() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
void OnEvent(lv_obj_t* obj, lv_event_t event);
|
||||
enum class States { Running, Stopped };
|
||||
|
||||
private:
|
||||
bool running;
|
||||
States currentState;
|
||||
TickType_t startTime;
|
||||
TickType_t tappedTime = 0;
|
||||
Controllers::MotorController& motorController;
|
||||
System::SystemTask& systemTask;
|
||||
uint16_t bpm = 120;
|
||||
uint8_t bpb = 4;
|
||||
uint8_t counter = 1;
|
||||
|
||||
lv_obj_t *bpmArc, *bpmTap, *bpmValue, *bpmLegend;
|
||||
lv_obj_t *bpbDropdown, *bpbLegend;
|
||||
lv_obj_t *playPause, *playPauseLabel;
|
||||
};
|
||||
}
|
@@ -32,11 +32,10 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr
|
||||
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
|
||||
lv_label_set_recolor(label, true);
|
||||
|
||||
|
||||
labelStep = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||
lv_label_set_text(labelStep, "Steps ---");
|
||||
|
||||
}
|
||||
|
||||
Motion::~Motion() {
|
||||
@@ -50,13 +49,12 @@ bool Motion::Refresh() {
|
||||
|
||||
lv_label_set_text_fmt(labelStep, "Steps %lu", motionController.NbSteps());
|
||||
|
||||
lv_label_set_text_fmt(label, "X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#", motionController.X() / 0x10, motionController.Y() / 0x10, motionController.Z() / 0x10);
|
||||
lv_label_set_text_fmt(label,
|
||||
"X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#",
|
||||
motionController.X() / 0x10,
|
||||
motionController.Y() / 0x10,
|
||||
motionController.Z() / 0x10);
|
||||
lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
bool Motion::OnButtonPushed() {
|
||||
running = false;
|
||||
return true;
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ namespace Pinetime {
|
||||
~Motion() override;
|
||||
|
||||
bool Refresh() override;
|
||||
bool OnButtonPushed() override;
|
||||
|
||||
private:
|
||||
Controllers::MotionController& motionController;
|
||||
@@ -29,10 +28,7 @@ namespace Pinetime {
|
||||
lv_obj_t* label;
|
||||
|
||||
lv_obj_t* labelStep;
|
||||
static constexpr uint8_t nbStepsBufferSize = 9;
|
||||
char nbStepsBuffer[nbStepsBufferSize + 1];
|
||||
bool running = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -119,7 +119,6 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
|
||||
constexpr int8_t MIDDLE_OFFSET = -25;
|
||||
txtArtist = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC);
|
||||
lv_label_set_anim_speed(txtArtist, 1);
|
||||
lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);
|
||||
lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID);
|
||||
lv_obj_set_width(txtArtist, LV_HOR_RES - 12);
|
||||
@@ -127,7 +126,6 @@ Music::Music(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Mus
|
||||
|
||||
txtTrack = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC);
|
||||
lv_label_set_anim_speed(txtTrack, 1);
|
||||
lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD);
|
||||
|
||||
lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID);
|
||||
@@ -303,4 +301,4 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,106 @@ using namespace Pinetime::Applications::Screens;
|
||||
|
||||
LV_FONT_DECLARE(lv_font_navi_80)
|
||||
|
||||
namespace {
|
||||
constexpr std::array<std::pair<const char*, const char*>, 86> m_iconMap = {{
|
||||
{"arrive-left", "\xEE\xA4\x81"},
|
||||
{"arrive-right", "\xEE\xA4\x82"},
|
||||
{"arrive-straight", "\xEE\xA4\x80"},
|
||||
{"arrive", "\xEE\xA4\x80"},
|
||||
{"close", "\xEE\xA4\x83"},
|
||||
{"continue-left", "\xEE\xA4\x85"},
|
||||
{"continue-right", "\xEE\xA4\x86"},
|
||||
{"continue-slight-left", "\xEE\xA4\x87"},
|
||||
{"continue-slight-right", "\xEE\xA4\x88"},
|
||||
{"continue-straight", "\xEE\xA4\x84"},
|
||||
{"continue-uturn", "\xEE\xA4\x89"},
|
||||
{"continue", "\xEE\xA4\x84"},
|
||||
{"depart-left", "\xEE\xA4\x8B"},
|
||||
{"depart-right", "\xEE\xA4\x8C"},
|
||||
{"depart-straight", "\xEE\xA4\x8A"},
|
||||
{"end-of-road-left", "\xEE\xA4\x8D"},
|
||||
{"end-of-road-right", "\xEE\xA4\x8E"},
|
||||
{"ferry", "\xEE\xA4\x8F"},
|
||||
{"flag", "\xEE\xA4\x90"},
|
||||
{"fork-left", "\xEE\xA4\x92"},
|
||||
{"fork-right", "\xEE\xA4\x93"},
|
||||
{"fork-slight-left", "\xEE\xA4\x94"},
|
||||
{"fork-slight-right", "\xEE\xA4\x95"},
|
||||
{"fork-straight", "\xEE\xA4\x96"},
|
||||
{"invalid", "\xEE\xA4\x84"},
|
||||
{"invalid-left", "\xEE\xA4\x85"},
|
||||
{"invalid-right", "\xEE\xA4\x86"},
|
||||
{"invalid-slight-left", "\xEE\xA4\x87"},
|
||||
{"invalid-slight-right", "\xEE\xA4\x88"},
|
||||
{"invalid-straight", "\xEE\xA4\x84"},
|
||||
{"invalid-uturn", "\xEE\xA4\x89"},
|
||||
{"merge-left", "\xEE\xA4\x97"},
|
||||
{"merge-right", "\xEE\xA4\x98"},
|
||||
{"merge-slight-left", "\xEE\xA4\x99"},
|
||||
{"merge-slight-right", "\xEE\xA4\x9A"},
|
||||
{"merge-straight", "\xEE\xA4\x84"},
|
||||
{"new-name-left", "\xEE\xA4\x85"},
|
||||
{"new-name-right", "\xEE\xA4\x86"},
|
||||
{"new-name-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"new-name-sharp-right", "\xEE\xA4\x9C"},
|
||||
{"new-name-slight-left", "\xEE\xA4\x87"},
|
||||
{"new-name-slight-right", "\xEE\xA4\x88"},
|
||||
{"new-name-straight", "\xEE\xA4\x84"},
|
||||
{"notification-left", "\xEE\xA4\x85"},
|
||||
{"notification-right", "\xEE\xA4\x86"},
|
||||
{"notification-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"notification-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"notification-slight-left", "\xEE\xA4\x87"},
|
||||
{"notification-slight-right", "\xEE\xA4\x88"},
|
||||
{"notification-straight", "\xEE\xA4\x84"},
|
||||
{"off-ramp-left", "\xEE\xA4\x9D"},
|
||||
{"off-ramp-right", "\xEE\xA4\x9E"},
|
||||
{"off-ramp-slight-left", "\xEE\xA4\x9F"},
|
||||
{"off-ramp-slight-right", "\xEE\xA4\xA0"},
|
||||
{"on-ramp-left", "\xEE\xA4\x85"},
|
||||
{"on-ramp-right", "\xEE\xA4\x86"},
|
||||
{"on-ramp-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"on-ramp-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"on-ramp-slight-left", "\xEE\xA4\x87"},
|
||||
{"on-ramp-slight-right", "\xEE\xA4\x88"},
|
||||
{"on-ramp-straight", "\xEE\xA4\x84"},
|
||||
{"rotary", "\xEE\xA4\xA1"},
|
||||
{"rotary-left", "\xEE\xA4\xA2"},
|
||||
{"rotary-right", "\xEE\xA4\xA3"},
|
||||
{"rotary-sharp-left", "\xEE\xA4\xA4"},
|
||||
{"rotary-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"rotary-slight-left", "\xEE\xA4\xA6"},
|
||||
{"rotary-slight-right", "\xEE\xA4\xA7"},
|
||||
{"rotary-straight", "\xEE\xA4\xA8"},
|
||||
{"roundabout", "\xEE\xA4\xA1"},
|
||||
{"roundabout-left", "\xEE\xA4\xA2"},
|
||||
{"roundabout-right", "\xEE\xA4\xA3"},
|
||||
{"roundabout-sharp-left", "\xEE\xA4\xA4"},
|
||||
{"roundabout-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"roundabout-slight-left", "\xEE\xA4\xA6"},
|
||||
{"roundabout-slight-right", "\xEE\xA4\xA7"},
|
||||
{"roundabout-straight", "\xEE\xA4\xA8"},
|
||||
{"turn-left", "\xEE\xA4\x85"},
|
||||
{"turn-right", "\xEE\xA4\x86"},
|
||||
{"turn-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"turn-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"turn-slight-left", "\xEE\xA4\x87"},
|
||||
{"turn-slight-right", "\xEE\xA4\x88"},
|
||||
{"turn-straight", "\xEE\xA4\x84"},
|
||||
{"updown", "\xEE\xA4\xA9"},
|
||||
{"uturn", "\xEE\xA4\x89"},
|
||||
}};
|
||||
|
||||
const char* iconForName(const std::string& icon) {
|
||||
for (auto iter : m_iconMap) {
|
||||
if (iter.first == icon) {
|
||||
return iter.second;
|
||||
}
|
||||
}
|
||||
return "\xEE\xA4\x90";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigation watchapp
|
||||
*
|
||||
@@ -68,27 +168,25 @@ Navigation::~Navigation() {
|
||||
}
|
||||
|
||||
bool Navigation::Refresh() {
|
||||
|
||||
if (m_flag != navService.getFlag()) {
|
||||
m_flag = navService.getFlag();
|
||||
lv_label_set_text(imgFlag, iconForName(m_flag));
|
||||
// lv_img_set_src_arr(imgFlag, iconForName(m_flag));
|
||||
if (flag != navService.getFlag()) {
|
||||
flag = navService.getFlag();
|
||||
lv_label_set_text(imgFlag, iconForName(flag));
|
||||
}
|
||||
|
||||
if (m_narrative != navService.getNarrative()) {
|
||||
m_narrative = navService.getNarrative();
|
||||
lv_label_set_text(txtNarrative, m_narrative.data());
|
||||
if (narrative != navService.getNarrative()) {
|
||||
narrative = navService.getNarrative();
|
||||
lv_label_set_text(txtNarrative, narrative.data());
|
||||
}
|
||||
|
||||
if (m_manDist != navService.getManDist()) {
|
||||
m_manDist = navService.getManDist();
|
||||
lv_label_set_text(txtManDist, m_manDist.data());
|
||||
if (manDist != navService.getManDist()) {
|
||||
manDist = navService.getManDist();
|
||||
lv_label_set_text(txtManDist, manDist.data());
|
||||
}
|
||||
|
||||
if (m_progress != navService.getProgress()) {
|
||||
m_progress = navService.getProgress();
|
||||
lv_bar_set_value(barProgress, m_progress, LV_ANIM_OFF);
|
||||
if (m_progress > 90) {
|
||||
if (progress != navService.getProgress()) {
|
||||
progress = navService.getProgress();
|
||||
lv_bar_set_value(barProgress, progress, LV_ANIM_OFF);
|
||||
if (progress > 90) {
|
||||
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
} else {
|
||||
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
|
||||
@@ -98,11 +196,4 @@ bool Navigation::Refresh() {
|
||||
return running;
|
||||
}
|
||||
|
||||
const char* Navigation::iconForName(std::string icon) {
|
||||
for (auto iter : m_iconMap) {
|
||||
if (iter.first == icon) {
|
||||
return iter.second;
|
||||
}
|
||||
}
|
||||
return "\xEE\xA4\x90";
|
||||
}
|
||||
|
||||
|
@@ -45,103 +45,10 @@ namespace Pinetime {
|
||||
|
||||
Pinetime::Controllers::NavigationService& navService;
|
||||
|
||||
std::string m_flag;
|
||||
std::string m_narrative;
|
||||
std::string m_manDist;
|
||||
int m_progress;
|
||||
|
||||
/** Watchapp */
|
||||
|
||||
const char* iconForName(std::string icon);
|
||||
|
||||
std::array<std::pair<std::string, const char*>, 89> m_iconMap = {{
|
||||
{"arrive-left", "\xEE\xA4\x81"},
|
||||
{"arrive-right", "\xEE\xA4\x82"},
|
||||
{"arrive-straight", "\xEE\xA4\x80"},
|
||||
{"arrive", "\xEE\xA4\x80"},
|
||||
{"close", "\xEE\xA4\x83"},
|
||||
{"continue-left", "\xEE\xA4\x85"},
|
||||
{"continue-right", "\xEE\xA4\x86"},
|
||||
{"continue-slight-left", "\xEE\xA4\x87"},
|
||||
{"continue-slight-right", "\xEE\xA4\x88"},
|
||||
{"continue-straight", "\xEE\xA4\x84"},
|
||||
{"continue-uturn", "\xEE\xA4\x89"},
|
||||
{"continue", "\xEE\xA4\x84"},
|
||||
{"depart-left", "\xEE\xA4\x8B"},
|
||||
{"depart-right", "\xEE\xA4\x8C"},
|
||||
{"depart-straight", "\xEE\xA4\x8A"},
|
||||
{"end-of-road-left", "\xEE\xA4\x8D"},
|
||||
{"end-of-road-right", "\xEE\xA4\x8E"},
|
||||
{"ferry", "\xEE\xA4\x8F"},
|
||||
{"flag", "\xEE\xA4\x90"},
|
||||
{"fork-left", "\xEE\xA4\x92"},
|
||||
{"fork-right", "\xEE\xA4\x93"},
|
||||
{"fork-slight-left", "\xEE\xA4\x94"},
|
||||
{"fork-slight-right", "\xEE\xA4\x95"},
|
||||
{"fork-straight", "\xEE\xA4\x96"},
|
||||
{"invalid", "\xEE\xA4\x84"},
|
||||
{"invalid-left", "\xEE\xA4\x85"},
|
||||
{"invalid-right", "\xEE\xA4\x86"},
|
||||
{"invalid-slight-left", "\xEE\xA4\x87"},
|
||||
{"invalid-slight-right", "\xEE\xA4\x88"},
|
||||
{"invalid-straight", "\xEE\xA4\x84"},
|
||||
{"invalid-uturn", "\xEE\xA4\x89"},
|
||||
{"merge-left", "\xEE\xA4\x97"},
|
||||
{"merge-right", "\xEE\xA4\x98"},
|
||||
{"merge-slight-left", "\xEE\xA4\x99"},
|
||||
{"merge-slight-right", "\xEE\xA4\x9A"},
|
||||
{"merge-straight", "\xEE\xA4\x84"},
|
||||
{"new-name-left", "\xEE\xA4\x85"},
|
||||
{"new-name-right", "\xEE\xA4\x86"},
|
||||
{"new-name-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"new-name-sharp-right", "\xEE\xA4\x9C"},
|
||||
{"new-name-slight-left", "\xEE\xA4\x87"},
|
||||
{"new-name-slight-right", "\xEE\xA4\x88"},
|
||||
{"new-name-straight", "\xEE\xA4\x84"},
|
||||
{"notification-left", "\xEE\xA4\x85"},
|
||||
{"notification-right", "\xEE\xA4\x86"},
|
||||
{"notification-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"notification-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"notification-slight-left", "\xEE\xA4\x87"},
|
||||
{"notification-slight-right", "\xEE\xA4\x88"},
|
||||
{"notification-straight", "\xEE\xA4\x84"},
|
||||
{"off-ramp-left", "\xEE\xA4\x9D"},
|
||||
{"off-ramp-right", "\xEE\xA4\x9E"},
|
||||
{"off-ramp-slight-left", "\xEE\xA4\x9F"},
|
||||
{"off-ramp-slight-right", "\xEE\xA4\xA0"},
|
||||
{"on-ramp-left", "\xEE\xA4\x85"},
|
||||
{"on-ramp-right", "\xEE\xA4\x86"},
|
||||
{"on-ramp-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"on-ramp-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"on-ramp-slight-left", "\xEE\xA4\x87"},
|
||||
{"on-ramp-slight-right", "\xEE\xA4\x88"},
|
||||
{"on-ramp-straight", "\xEE\xA4\x84"},
|
||||
{"rotary", "\xEE\xA4\xA1"},
|
||||
{"rotary-left", "\xEE\xA4\xA2"},
|
||||
{"rotary-right", "\xEE\xA4\xA3"},
|
||||
{"rotary-sharp-left", "\xEE\xA4\xA4"},
|
||||
{"rotary-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"rotary-slight-left", "\xEE\xA4\xA6"},
|
||||
{"rotary-slight-right", "\xEE\xA4\xA7"},
|
||||
{"rotary-straight", "\xEE\xA4\xA8"},
|
||||
{"roundabout", "\xEE\xA4\xA1"},
|
||||
{"roundabout-left", "\xEE\xA4\xA2"},
|
||||
{"roundabout-right", "\xEE\xA4\xA3"},
|
||||
{"roundabout-sharp-left", "\xEE\xA4\xA4"},
|
||||
{"roundabout-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"roundabout-slight-left", "\xEE\xA4\xA6"},
|
||||
{"roundabout-slight-right", "\xEE\xA4\xA7"},
|
||||
{"roundabout-straight", "\xEE\xA4\xA8"},
|
||||
{"turn-left", "\xEE\xA4\x85"},
|
||||
{"turn-right", "\xEE\xA4\x86"},
|
||||
{"turn-sharp-left", "\xEE\xA4\x9B"},
|
||||
{"turn-sharp-right", "\xEE\xA4\xA5"},
|
||||
{"turn-slight-left", "\xEE\xA4\x87"},
|
||||
{"turn-slight-right", "\xEE\xA4\x88"},
|
||||
{"turn-straight", "\xEE\xA4\x84"},
|
||||
{"updown", "\xEE\xA4\xA9"},
|
||||
{"uturn", "\xEE\xA4\x89"},
|
||||
}};
|
||||
std::string flag;
|
||||
std::string narrative;
|
||||
std::string manDist;
|
||||
int progress;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -185,10 +185,10 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||
lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
|
||||
lv_obj_set_pos(container1, 0, 50);
|
||||
lv_obj_set_width(container1, 240);
|
||||
lv_obj_set_height(container1, 190);
|
||||
lv_obj_set_size(container1, LV_HOR_RES, 190);
|
||||
|
||||
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
|
||||
lv_cont_set_fit(container1, LV_FIT_NONE);
|
||||
|
||||
lv_obj_t* alert_count = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb);
|
||||
@@ -198,7 +198,15 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||
lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x888888));
|
||||
if (title == nullptr)
|
||||
title = "Notification";
|
||||
char* pchar;
|
||||
pchar = strchr(title, '\n');
|
||||
while (pchar != nullptr) {
|
||||
*pchar = ' ';
|
||||
pchar = strchr(pchar + 1, '\n');
|
||||
}
|
||||
lv_label_set_text(alert_type, title);
|
||||
lv_label_set_long_mode(alert_type, LV_LABEL_LONG_SROLL_CIRC);
|
||||
lv_obj_set_width(alert_type, 180);
|
||||
lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16);
|
||||
|
||||
/////////
|
||||
@@ -211,6 +219,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||
lv_label_set_text(alert_subject, msg);
|
||||
} break;
|
||||
case Controllers::NotificationManager::Categories::IncomingCall: {
|
||||
lv_obj_set_height(container1, 108);
|
||||
lv_obj_t* alert_subject = lv_label_create(container1, nullptr);
|
||||
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
|
||||
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
||||
@@ -223,38 +232,29 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
||||
lv_obj_set_width(alert_caller, LV_HOR_RES - 20);
|
||||
lv_label_set_text(alert_caller, msg);
|
||||
|
||||
lv_obj_t* callBtnContainer = lv_cont_create(container1, NULL);
|
||||
lv_obj_set_width(callBtnContainer, 240);
|
||||
lv_obj_set_height(callBtnContainer, 90);
|
||||
lv_cont_set_layout(callBtnContainer, LV_LAYOUT_ROW_MID);
|
||||
|
||||
lv_obj_set_style_local_bg_color(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
||||
lv_obj_set_style_local_pad_all(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_style_local_margin_top(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 40);
|
||||
lv_obj_set_style_local_margin_left(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, -8);
|
||||
lv_obj_set_style_local_pad_inner(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
||||
lv_obj_set_style_local_border_width(callBtnContainer, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
|
||||
bt_accept = lv_btn_create(callBtnContainer, nullptr);
|
||||
bt_accept = lv_btn_create(lv_scr_act(), nullptr);
|
||||
bt_accept->user_data = this;
|
||||
lv_obj_set_event_cb(bt_accept, AcceptIncomingCallEventHandler);
|
||||
lv_obj_set_size(bt_accept, (LV_HOR_RES / 3) - 5, 80);
|
||||
lv_obj_set_size(bt_accept, 76, 76);
|
||||
lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||
label_accept = lv_label_create(bt_accept, nullptr);
|
||||
lv_label_set_text(label_accept, Symbols::phone);
|
||||
lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
|
||||
bt_reject = lv_btn_create(callBtnContainer, nullptr);
|
||||
bt_reject = lv_btn_create(lv_scr_act(), nullptr);
|
||||
bt_reject->user_data = this;
|
||||
lv_obj_set_event_cb(bt_reject, RejectIncomingCallEventHandler);
|
||||
lv_obj_set_size(bt_reject, (LV_HOR_RES / 3) - 5, 80);
|
||||
lv_obj_set_size(bt_reject, 76, 76);
|
||||
lv_obj_align(bt_reject, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
label_reject = lv_label_create(bt_reject, nullptr);
|
||||
lv_label_set_text(label_reject, Symbols::phoneSlash);
|
||||
lv_obj_set_style_local_bg_color(bt_reject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
|
||||
bt_mute = lv_btn_create(callBtnContainer, nullptr);
|
||||
bt_mute = lv_btn_create(lv_scr_act(), nullptr);
|
||||
bt_mute->user_data = this;
|
||||
lv_obj_set_event_cb(bt_mute, MuteIncomingCallEventHandler);
|
||||
lv_obj_set_size(bt_mute, (LV_HOR_RES / 3) - 5, 80);
|
||||
lv_obj_set_size(bt_mute, 76, 76);
|
||||
lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||
label_mute = lv_label_create(bt_mute, nullptr);
|
||||
lv_label_set_text(label_mute, Symbols::volumMute);
|
||||
lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
|
@@ -4,98 +4,31 @@
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
const uint8_t paddle_map[] = {
|
||||
0xfc, 0xfe, 0xfc, 0xff, /*Color of index 0*/
|
||||
0xff, 0xff, 0xff, 0xff, /*Color of index 1*/
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const uint8_t ball_map[] = {
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 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, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 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, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
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, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 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, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 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, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 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, 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, 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, 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, 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, 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, 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, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed,
|
||||
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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x6f, 0xed, 0x6f, 0xed, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 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, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 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, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
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, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 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, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed, 0x6f, 0xed,
|
||||
};
|
||||
}
|
||||
|
||||
Paddle::Paddle(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl {lvgl} {
|
||||
app->SetTouchMode(DisplayApp::TouchModes::Polling);
|
||||
|
||||
background = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_size(background, LV_HOR_RES + 1, LV_VER_RES);
|
||||
lv_obj_set_pos(background, -1, 0);
|
||||
lv_obj_set_style_local_radius(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_obj_set_style_local_border_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_set_style_local_border_width(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 1);
|
||||
|
||||
points = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(points, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
|
||||
lv_label_set_text(points, "0000");
|
||||
lv_obj_set_style_local_text_color(points, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x444444));
|
||||
lv_obj_align(points, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0);
|
||||
lv_obj_align(points, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10);
|
||||
|
||||
paddle.header.always_zero = 0;
|
||||
paddle.header.w = 4;
|
||||
paddle.header.h = 60;
|
||||
paddle.data_size = 68;
|
||||
paddle.header.cf = LV_IMG_CF_INDEXED_1BIT;
|
||||
paddle.data = paddle_map;
|
||||
paddle_image = lv_img_create(lv_scr_act(), nullptr);
|
||||
lv_img_set_src(paddle_image, &paddle);
|
||||
paddle = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_color(paddle, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_set_style_local_radius(paddle, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_size(paddle, 4, 60);
|
||||
|
||||
ball.header.always_zero = 0;
|
||||
ball.header.w = 24;
|
||||
ball.header.h = 24;
|
||||
ball.data_size = 24 * 24 * LV_COLOR_SIZE / 8;
|
||||
ball.header.cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
|
||||
ball.data = ball_map;
|
||||
ball_image = lv_img_create(lv_scr_act(), nullptr);
|
||||
lv_img_set_src(ball_image, &ball);
|
||||
ball = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_color(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_set_style_local_radius(ball, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
|
||||
lv_obj_set_size(ball, ballSize, ballSize);
|
||||
}
|
||||
|
||||
Paddle::~Paddle() {
|
||||
@@ -105,41 +38,37 @@ Paddle::~Paddle() {
|
||||
}
|
||||
|
||||
bool Paddle::Refresh() {
|
||||
if ((counter++ % 5) == 0) {
|
||||
counter = 0;
|
||||
ballX += dx;
|
||||
ballY += dy;
|
||||
|
||||
ballX += dx;
|
||||
ballY += dy;
|
||||
lv_obj_set_pos(ball, ballX, ballY);
|
||||
|
||||
lv_obj_set_pos(ball_image, ballX, ballY);
|
||||
// checks if it has touched the sides (floor and ceiling)
|
||||
if (ballY <= 1 || ballY >= LV_VER_RES - ballSize - 2) {
|
||||
dy *= -1;
|
||||
}
|
||||
|
||||
// checks if it has touched the sides (floor and ceiling)
|
||||
if (ballY <= 0 || ballY >= 215) {
|
||||
dy *= -1;
|
||||
}
|
||||
// checks if it has touched the side (left side)
|
||||
if (ballX >= LV_VER_RES - ballSize - 1) {
|
||||
dx *= -1;
|
||||
}
|
||||
|
||||
// checks if it has touched the side (left side)
|
||||
if (ballX >= 215) {
|
||||
dx *= -1;
|
||||
}
|
||||
|
||||
// checks if it is in the position of the paddle
|
||||
if (ballY <= (paddleBottomY + 16) && ballY >= (paddleTopY - 8)) {
|
||||
if (ballX >= 0 && ballX < 4) {
|
||||
lv_obj_set_pos(ball_image, 5, ballY);
|
||||
// checks if it is in the position of the paddle
|
||||
if (dx < 0 && ballX <= 4) {
|
||||
if (ballX >= -ballSize / 4) {
|
||||
if (ballY <= (paddlePos + 30 - ballSize / 4) && ballY >= (paddlePos - 30 - ballSize + ballSize / 4)) {
|
||||
dx *= -1;
|
||||
score++;
|
||||
}
|
||||
}
|
||||
|
||||
// checks if it has gone behind the paddle
|
||||
else if (ballX <= -40) {
|
||||
ballX = 107;
|
||||
ballY = 107;
|
||||
else if (ballX <= -ballSize * 2) {
|
||||
ballX = (LV_HOR_RES - ballSize) / 2;
|
||||
ballY = (LV_VER_RES - ballSize) / 2;
|
||||
score = 0;
|
||||
}
|
||||
lv_label_set_text_fmt(points, "%04d", score);
|
||||
}
|
||||
lv_label_set_text_fmt(points, "%04d", score);
|
||||
return running;
|
||||
}
|
||||
|
||||
@@ -148,11 +77,8 @@ bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
}
|
||||
|
||||
bool Paddle::OnTouchEvent(uint16_t x, uint16_t y) {
|
||||
lv_obj_set_pos(
|
||||
paddle_image,
|
||||
0,
|
||||
y - 30); // sets the center paddle pos. (30px offset) with the the y_coordinate of the finger and defaults the x_coordinate to 0
|
||||
paddleTopY = y - 30; // refreshes the upper extreme of the paddle
|
||||
paddleBottomY = y + 30; // refreshes the lower extreme of the paddle
|
||||
// sets the center paddle pos. (30px offset) with the the y_coordinate of the finger
|
||||
lv_obj_set_pos(paddle, 0, y - 30);
|
||||
paddlePos = y;
|
||||
return true;
|
||||
}
|
||||
|
@@ -24,24 +24,22 @@ namespace Pinetime {
|
||||
private:
|
||||
Pinetime::Components::LittleVgl& lvgl;
|
||||
|
||||
int paddleBottomY = 90; // bottom extreme of the paddle
|
||||
int paddleTopY = 150; // top extreme of the paddle
|
||||
const uint8_t ballSize = 16;
|
||||
|
||||
int ballX = 107; // Initial x_coordinate for the ball (12px offset from the center to counteract the ball's 24px size)
|
||||
int ballY = 107; // Initial y_coordinate for the ball
|
||||
uint16_t paddlePos = 30; // Paddle center
|
||||
|
||||
int dx = 2; // Velocity of the ball in the x_coordinate
|
||||
int dy = 3; // Velocity of the ball in the y_coordinate
|
||||
int16_t ballX = (LV_HOR_RES - ballSize) / 2;
|
||||
int16_t ballY = (LV_VER_RES - ballSize) / 2;
|
||||
|
||||
int counter = 0; // init Frame refresh limit counter
|
||||
int score = 0;
|
||||
int8_t dx = 2; // Velocity of the ball in the x_coordinate
|
||||
int8_t dy = 3; // Velocity of the ball in the y_coordinate
|
||||
|
||||
lv_img_dsc_t paddle;
|
||||
lv_img_dsc_t ball;
|
||||
uint16_t score = 0;
|
||||
|
||||
lv_obj_t* points;
|
||||
lv_obj_t* paddle_image; // pointer to paddle image
|
||||
lv_obj_t* ball_image; // pointer to ball image
|
||||
lv_obj_t* paddle;
|
||||
lv_obj_t* ball;
|
||||
lv_obj_t* background;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
340
src/displayapp/screens/PineTimeStyle.cpp
Normal file
340
src/displayapp/screens/PineTimeStyle.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* This file is part of the Infinitime distribution (https://github.com/JF002/Infinitime).
|
||||
* Copyright (c) 2021 Kieran Cawthray.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* PineTimeStyle watchface for Infinitime created by Kieran Cawthray
|
||||
* Based on WatchFaceDigital
|
||||
* Style/layout copied from TimeStyle for Pebble by Dan Tilden (github.com/tilden)
|
||||
*/
|
||||
|
||||
#include "PineTimeStyle.h"
|
||||
#include <date/date.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <cstdio>
|
||||
#include "BatteryIcon.h"
|
||||
#include "BleIcon.h"
|
||||
#include "NotificationIcon.h"
|
||||
#include "Symbols.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/motion/MotionController.h"
|
||||
#include "components/settings/Settings.h"
|
||||
#include "../DisplayApp.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
PineTimeStyle::PineTimeStyle(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::MotionController& motionController)
|
||||
: Screen(app),
|
||||
currentDateTime {{}},
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
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 */
|
||||
|
||||
timebar = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
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, lv_color_hex(0x008080));
|
||||
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, lv_color_hex(0x008080));
|
||||
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, lv_color_hex(0x008080));
|
||||
lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3);
|
||||
lv_label_set_text(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 */
|
||||
|
||||
sidebar = lv_obj_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_bg_color(sidebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x008080));
|
||||
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);
|
||||
|
||||
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
lv_obj_align(batteryPlug, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
|
||||
|
||||
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25);
|
||||
|
||||
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
|
||||
lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 40);
|
||||
|
||||
/* 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, 4);
|
||||
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, "");
|
||||
}
|
||||
|
||||
PineTimeStyle::~PineTimeStyle() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool PineTimeStyle::Refresh() {
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
if (batteryPercentRemaining.IsUpdated()) {
|
||||
auto batteryPercent = batteryPercentRemaining.Get();
|
||||
if (batteryController.IsCharging()) {
|
||||
auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
|
||||
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
|
||||
lv_obj_realign(batteryPlug);
|
||||
lv_label_set_text(batteryIcon, "");
|
||||
} else {
|
||||
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
|
||||
lv_label_set_text(batteryPlug, "");
|
||||
}
|
||||
}
|
||||
|
||||
bleState = bleController.IsConnected();
|
||||
if (bleState.IsUpdated()) {
|
||||
if (bleState.Get() == true) {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(true));
|
||||
lv_obj_realign(bleIcon);
|
||||
} else {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(false));
|
||||
}
|
||||
}
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
if (notificationState.IsUpdated()) {
|
||||
if (notificationState.Get() == true) {
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
|
||||
lv_obj_realign(notificationIcon);
|
||||
} else {
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
}
|
||||
}
|
||||
|
||||
currentDateTime = dateTimeController.CurrentDateTime();
|
||||
|
||||
if (currentDateTime.IsUpdated()) {
|
||||
auto newDateTime = currentDateTime.Get();
|
||||
|
||||
auto dp = date::floor<date::days>(newDateTime);
|
||||
auto time = date::make_time(newDateTime - dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
auto year = (int) yearMonthDay.year();
|
||||
auto month = static_cast<Pinetime::Controllers::DateTime::Months>((unsigned) yearMonthDay.month());
|
||||
auto day = (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[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] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] ||
|
||||
minutesChar[1] != displayedChar[3]) {
|
||||
displayedChar[0] = hoursChar[0];
|
||||
displayedChar[1] = hoursChar[1];
|
||||
displayedChar[2] = minutesChar[0];
|
||||
displayedChar[3] = minutesChar[1];
|
||||
|
||||
char hourStr[3];
|
||||
char minStr[3];
|
||||
|
||||
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
|
||||
lv_label_set_text(timeAMPM, ampmChar);
|
||||
}
|
||||
|
||||
/* Display the time as 2 pairs of digits */
|
||||
sprintf(hourStr, "%c%c", hoursChar[0], hoursChar[1]);
|
||||
lv_label_set_text(timeDD1, hourStr);
|
||||
|
||||
sprintf(minStr, "%c%c", minutesChar[0], minutesChar[1]);
|
||||
lv_label_set_text(timeDD2, minStr);
|
||||
}
|
||||
|
||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
char dayOfWeekStr[4];
|
||||
char dayStr[3];
|
||||
char monthStr[4];
|
||||
|
||||
sprintf(dayOfWeekStr, "%s", dateTimeController.DayOfWeekShortToString());
|
||||
sprintf(dayStr, "%d", day);
|
||||
sprintf(monthStr, "%s", dateTimeController.MonthShortToString());
|
||||
|
||||
lv_label_set_text(dateDayOfWeek, dayOfWeekStr);
|
||||
lv_label_set_text(dateDay, dayStr);
|
||||
lv_obj_realign(dateDay);
|
||||
lv_label_set_text(dateMonth, monthStr);
|
||||
|
||||
currentYear = year;
|
||||
currentMonth = month;
|
||||
currentDayOfWeek = dayOfWeek;
|
||||
currentDay = day;
|
||||
}
|
||||
}
|
||||
|
||||
stepCount = motionController.NbSteps();
|
||||
motionSensorOk = motionController.IsSensorOk();
|
||||
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
|
||||
lv_gauge_set_value(stepGauge, 0, (stepCount.Get() / (settingsController.GetStepsGoal() / 100)));
|
||||
lv_obj_realign(stepGauge);
|
||||
if (stepCount.Get() > settingsController.GetStepsGoal()) {
|
||||
lv_obj_set_style_local_line_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
return running;
|
||||
}
|
86
src/displayapp/screens/PineTimeStyle.h
Normal file
86
src/displayapp/screens/PineTimeStyle.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/src/lv_core/lv_obj.h>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "Screen.h"
|
||||
#include "ScreenList.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class NotificationManager;
|
||||
class HeartRateController;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
class PineTimeStyle : public Screen {
|
||||
public:
|
||||
PineTimeStyle(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::MotionController& motionController);
|
||||
~PineTimeStyle() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
void OnObjectEvent(lv_obj_t* pObj, lv_event_t i);
|
||||
|
||||
private:
|
||||
char displayedChar[5];
|
||||
|
||||
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;
|
||||
|
||||
DirtyValue<uint8_t> batteryPercentRemaining {};
|
||||
DirtyValue<bool> bleState {};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
|
||||
DirtyValue<bool> motionSensorOk {};
|
||||
DirtyValue<uint32_t> stepCount {};
|
||||
DirtyValue<bool> notificationState {};
|
||||
|
||||
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* batteryPlug;
|
||||
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* heartbeatIcon;
|
||||
lv_obj_t* heartbeatValue;
|
||||
lv_obj_t* heartbeatBpm;
|
||||
lv_obj_t* notificationIcon;
|
||||
lv_obj_t* stepGauge;
|
||||
lv_color_t needle_colors[1];
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::MotionController& motionController;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,8 +13,12 @@ namespace Pinetime {
|
||||
DirtyValue() = default; // Use NSDMI
|
||||
explicit DirtyValue(T const& v) : value {v} {
|
||||
} // Use MIL and const-lvalue-ref
|
||||
bool IsUpdated() const {
|
||||
return isUpdated;
|
||||
bool IsUpdated() {
|
||||
if (this->isUpdated) {
|
||||
this->isUpdated = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
T const& Get() {
|
||||
this->isUpdated = false;
|
||||
|
@@ -15,12 +15,17 @@ namespace Pinetime {
|
||||
public:
|
||||
ScreenList(DisplayApp* app,
|
||||
uint8_t initScreen,
|
||||
std::array<std::function<std::unique_ptr<Screen>()>, N>&& screens,
|
||||
const std::array<std::function<std::unique_ptr<Screen>()>, N>&& screens,
|
||||
ScreenListModes mode)
|
||||
: Screen(app), initScreen {initScreen}, screens {std::move(screens)}, mode {mode}, current {this->screens[initScreen]()} {
|
||||
screenIndex = initScreen;
|
||||
: Screen(app), initScreen {initScreen}, screens {std::move(screens)}, mode {mode}, screenIndex{initScreen}, current {this->screens[initScreen]()} {
|
||||
|
||||
}
|
||||
|
||||
ScreenList(const ScreenList&) = delete;
|
||||
ScreenList& operator=(const ScreenList&) = delete;
|
||||
ScreenList(ScreenList&&) = delete;
|
||||
ScreenList& operator=(ScreenList&&) = delete;
|
||||
|
||||
~ScreenList() override {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
@@ -97,7 +102,7 @@ namespace Pinetime {
|
||||
|
||||
private:
|
||||
uint8_t initScreen = 0;
|
||||
std::array<std::function<std::unique_ptr<Screen>()>, N> screens;
|
||||
const std::array<std::function<std::unique_ptr<Screen>()>, N> screens;
|
||||
ScreenListModes mode = ScreenListModes::UpDown;
|
||||
|
||||
uint8_t screenIndex = 0;
|
||||
|
@@ -5,20 +5,17 @@
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
Steps::Steps(
|
||||
Pinetime::Applications::DisplayApp *app,
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::Settings &settingsController)
|
||||
: Screen(app),
|
||||
motionController{motionController},
|
||||
settingsController{settingsController} {
|
||||
Steps::Steps(Pinetime::Applications::DisplayApp* app,
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::Settings& settingsController)
|
||||
: Screen(app), motionController {motionController}, settingsController {settingsController} {
|
||||
|
||||
stepsArc = lv_arc_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
|
||||
lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2);
|
||||
lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0x0000FF));
|
||||
lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
|
||||
lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2);
|
||||
lv_obj_set_style_local_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_arc_set_range(stepsArc, 0, 500);
|
||||
@@ -30,27 +27,26 @@ Steps::Steps(
|
||||
|
||||
lSteps = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
|
||||
lv_obj_set_style_local_text_font(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
|
||||
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
|
||||
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_t * lstepsL = lv_label_create(lv_scr_act(), nullptr);
|
||||
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_label_set_text_static(lstepsL, "Steps");
|
||||
lv_obj_align(lstepsL, lSteps, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
||||
|
||||
lv_obj_t * lstepsGoal = lv_label_create(lv_scr_act(), nullptr);
|
||||
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%i", settingsController.GetStepsGoal());
|
||||
lv_label_set_text_fmt(lstepsGoal, "Goal\n%lu", 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_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_t* backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
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_static(backgroundLabel, "");
|
||||
|
||||
}
|
||||
|
||||
Steps::~Steps() {
|
||||
@@ -58,15 +54,13 @@ Steps::~Steps() {
|
||||
}
|
||||
|
||||
bool Steps::Refresh() {
|
||||
|
||||
|
||||
stepsCount = motionController.NbSteps();
|
||||
|
||||
lv_label_set_text_fmt(lSteps,"%li", stepsCount);
|
||||
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
|
||||
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -20);
|
||||
|
||||
|
||||
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -45,38 +45,51 @@ static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
stopWatch->stopLapBtnEventHandler(event);
|
||||
}
|
||||
|
||||
StopWatch::StopWatch(DisplayApp* app)
|
||||
StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
|
||||
: Screen(app),
|
||||
systemTask {systemTask},
|
||||
running {true},
|
||||
currentState {States::Init},
|
||||
currentEvent {Events::Stop},
|
||||
startTime {},
|
||||
oldTimeElapsed {},
|
||||
currentTimeSeparated {},
|
||||
lapBuffer {},
|
||||
lapNr {},
|
||||
lapPressed {false} {
|
||||
lapNr {} {
|
||||
|
||||
time = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
lv_label_set_text(time, "00:00");
|
||||
lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -45);
|
||||
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45);
|
||||
|
||||
msecTime = lv_label_create(lv_scr_act(), nullptr);
|
||||
// lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
lv_label_set_text(msecTime, "00");
|
||||
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 108, 3);
|
||||
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3);
|
||||
|
||||
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);
|
||||
lv_obj_set_height(btnPlayPause, 50);
|
||||
lv_obj_set_width(btnPlayPause, 115);
|
||||
lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
|
||||
lv_label_set_text(txtPlayPause, Symbols::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_set_height(btnStopLap, 50);
|
||||
lv_obj_set_width(btnStopLap, 115);
|
||||
lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||
lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DISABLED, lv_color_hex(0x080808));
|
||||
txtStopLap = lv_label_create(btnStopLap, nullptr);
|
||||
lv_obj_set_style_local_text_color(txtStopLap, LV_BTN_PART_MAIN, LV_STATE_DISABLED, lv_color_hex(0x888888));
|
||||
lv_label_set_text(txtStopLap, Symbols::stop);
|
||||
lv_obj_set_state(btnStopLap, LV_STATE_DISABLED);
|
||||
lv_obj_set_state(txtStopLap, LV_STATE_DISABLED);
|
||||
|
||||
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_set_style_local_text_color(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
@@ -88,140 +101,103 @@ StopWatch::StopWatch(DisplayApp* app)
|
||||
lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
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() {
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void StopWatch::reset() {
|
||||
currentState = States::Init;
|
||||
oldTimeElapsed = 0;
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
|
||||
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;
|
||||
lv_obj_set_state(btnStopLap, LV_STATE_DISABLED);
|
||||
lv_obj_set_state(txtStopLap, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
void StopWatch::start() {
|
||||
lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT);
|
||||
lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_label_set_text(txtPlayPause, Symbols::pause);
|
||||
lv_label_set_text(txtStopLap, Symbols::lapsFlag);
|
||||
startTime = xTaskGetTickCount();
|
||||
currentState = States::Running;
|
||||
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
|
||||
}
|
||||
|
||||
void StopWatch::pause() {
|
||||
startTime = 0;
|
||||
// Store the current time elapsed in cache
|
||||
oldTimeElapsed += timeElapsed;
|
||||
currentState = States::Halted;
|
||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||
lv_label_set_text(txtStopLap, Symbols::stop);
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
|
||||
}
|
||||
|
||||
bool StopWatch::Refresh() {
|
||||
// @startuml CHIP8_state
|
||||
// State "Init" as init
|
||||
// State "Running" as run
|
||||
// State "Halted" as halt
|
||||
if (currentState == States::Running) {
|
||||
timeElapsed = calculateDelta(startTime, xTaskGetTickCount());
|
||||
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
|
||||
|
||||
// [*] --> 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 != nullptr) {
|
||||
lv_obj_del(btnStopLap);
|
||||
btnStopLap = nullptr;
|
||||
}
|
||||
// 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.hundredths);
|
||||
|
||||
if (lapPressed == true) {
|
||||
if (lapBuffer[1]) {
|
||||
lv_label_set_text_fmt(
|
||||
lapOneText, "#%2d %2d:%02d.%02d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->hundredths);
|
||||
}
|
||||
if (lapBuffer[0]) {
|
||||
lv_label_set_text_fmt(
|
||||
lapTwoText, "#%2d %2d:%02d.%02d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->hundredths);
|
||||
}
|
||||
// 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;
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
|
||||
} else {
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
}
|
||||
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;
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
|
||||
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (event != LV_EVENT_PRESSED) {
|
||||
return;
|
||||
}
|
||||
if (currentState == States::Init) {
|
||||
start();
|
||||
} else if (currentState == States::Running) {
|
||||
pause();
|
||||
} else if (currentState == States::Halted) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
if (event != LV_EVENT_PRESSED) {
|
||||
return;
|
||||
}
|
||||
// If running, then this button is used to save laps
|
||||
if (currentState == States::Running) {
|
||||
lapBuffer.addLaps(currentTimeSeparated);
|
||||
lapNr++;
|
||||
if (lapBuffer[1]) {
|
||||
lv_label_set_text_fmt(
|
||||
lapOneText, "#%2d %2d:%02d.%02d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->hundredths);
|
||||
}
|
||||
if (lapBuffer[0]) {
|
||||
lv_label_set_text_fmt(lapTwoText, "#%2d %2d:%02d.%02d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->hundredths);
|
||||
}
|
||||
} else if (currentState == States::Halted) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool StopWatch::OnButtonPushed() {
|
||||
if (currentState == States::Running) {
|
||||
pause();
|
||||
} else {
|
||||
running = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -8,13 +8,12 @@
|
||||
#include "portmacro_cmsis.h"
|
||||
|
||||
#include <array>
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
namespace Pinetime::Applications::Screens {
|
||||
|
||||
enum class States { Init, Running, Halted };
|
||||
|
||||
enum class Events { Play, Pause, Stop };
|
||||
|
||||
struct TimeSeparated_t {
|
||||
int mins;
|
||||
int secs;
|
||||
@@ -63,23 +62,28 @@ namespace Pinetime::Applications::Screens {
|
||||
|
||||
class StopWatch : public Screen {
|
||||
public:
|
||||
StopWatch(DisplayApp* app);
|
||||
StopWatch(DisplayApp* app, System::SystemTask& systemTask);
|
||||
~StopWatch() override;
|
||||
bool Refresh() override;
|
||||
|
||||
void playPauseBtnEventHandler(lv_event_t event);
|
||||
void stopLapBtnEventHandler(lv_event_t event);
|
||||
bool OnButtonPushed() override;
|
||||
|
||||
void reset();
|
||||
void start();
|
||||
void pause();
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
TickType_t timeElapsed;
|
||||
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;
|
||||
int lapNr = 0;
|
||||
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
|
||||
lv_obj_t *lapOneText, *lapTwoText;
|
||||
};
|
||||
|
@@ -38,7 +38,12 @@ namespace Pinetime {
|
||||
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* hourGlass = "\xEF\x89\x92";
|
||||
static constexpr const char* lapsFlag = "\xEF\x80\xA4";
|
||||
static constexpr const char* drum = "\xEF\x95\xA9";
|
||||
static constexpr const char* chartLine = "\xEF\x88\x81";
|
||||
static constexpr const char* eye = "\xEF\x81\xAE";
|
||||
static constexpr const char* home = "\xEF\x80\x95";
|
||||
|
||||
// lv_font_sys_48.c
|
||||
static constexpr const char* settings = "\xEE\xA4\x82"; // e902
|
||||
|
@@ -3,26 +3,44 @@
|
||||
#include "../DisplayApp.h"
|
||||
#include "Label.h"
|
||||
#include "Version.h"
|
||||
#include "BootloaderVersion.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/motion/MotionController.h"
|
||||
#include "drivers/Watchdog.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
const char* ToString(const Pinetime::Controllers::MotionController::DeviceTypes deviceType) {
|
||||
switch (deviceType) {
|
||||
case Pinetime::Controllers::MotionController::DeviceTypes::BMA421:
|
||||
return "BMA421";
|
||||
case Pinetime::Controllers::MotionController::DeviceTypes::BMA425:
|
||||
return "BMA425";
|
||||
case Pinetime::Controllers::MotionController::DeviceTypes::Unknown:
|
||||
return "???";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
|
||||
Pinetime::Controllers::DateTime& dateTimeController,
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Pinetime::Controllers::BrightnessController& brightnessController,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
Pinetime::Drivers::WatchdogView& watchdog)
|
||||
Pinetime::Drivers::WatchdogView& watchdog,
|
||||
Pinetime::Controllers::MotionController& motionController)
|
||||
: Screen(app),
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
brightnessController {brightnessController},
|
||||
bleController {bleController},
|
||||
watchdog {watchdog},
|
||||
motionController{motionController},
|
||||
screens {app,
|
||||
0,
|
||||
{[this]() -> std::unique_ptr<Screen> {
|
||||
@@ -54,11 +72,6 @@ bool SystemInfo::Refresh() {
|
||||
return running;
|
||||
}
|
||||
|
||||
bool SystemInfo::OnButtonPushed() {
|
||||
running = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return screens.OnTouchEvent(event);
|
||||
}
|
||||
@@ -68,24 +81,26 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() {
|
||||
lv_label_set_recolor(label, true);
|
||||
lv_label_set_text_fmt(label,
|
||||
"#FFFF00 InfiniTime#\n\n"
|
||||
"#444444 Version# %ld.%ld.%ld\n\n"
|
||||
"#444444 Version# %ld.%ld.%ld\n"
|
||||
"#444444 Short Ref# %s\n"
|
||||
"#444444 Build date#\n"
|
||||
"%s\n"
|
||||
"%s\n",
|
||||
"%s\n\n"
|
||||
"#444444 Bootloader# %s",
|
||||
Version::Major(),
|
||||
Version::Minor(),
|
||||
Version::Patch(),
|
||||
Version::GitCommitHash(),
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
__TIME__,
|
||||
BootloaderVersion::VersionString());
|
||||
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
|
||||
return std::make_unique<Screens::Label>(0, 5, app, label);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
|
||||
auto batteryPercent = static_cast<uint8_t>(batteryController.PercentRemaining());
|
||||
float batteryVoltage = batteryController.Voltage();
|
||||
|
||||
auto batteryPercent = batteryController.PercentRemaining();
|
||||
auto resetReason = [this]() {
|
||||
switch (watchdog.ResetReason()) {
|
||||
case Drivers::Watchdog::ResetReasons::Watchdog:
|
||||
@@ -124,25 +139,16 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
|
||||
uptimeSeconds = uptimeSeconds % secondsInAMinute;
|
||||
// TODO handle more than 100 days of uptime
|
||||
|
||||
if (batteryPercent == -1)
|
||||
batteryPercent = 0;
|
||||
|
||||
// hack to not use the flot functions from printf
|
||||
uint8_t batteryVoltageBytes[2];
|
||||
batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
|
||||
batteryVoltageBytes[0] =
|
||||
static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
|
||||
//
|
||||
|
||||
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_recolor(label, true);
|
||||
lv_label_set_text_fmt(label,
|
||||
"#444444 Date# %02d/%02d/%04d\n"
|
||||
"#444444 Time# %02d:%02d:%02d\n"
|
||||
"#444444 Uptime#\n %02lud %02lu:%02lu:%02lu\n"
|
||||
"#444444 Battery# %d%%/%1i.%02iv\n"
|
||||
"#444444 Battery# %d%%/%03imV\n"
|
||||
"#444444 Backlight# %s\n"
|
||||
"#444444 Last reset# %s\n",
|
||||
"#444444 Last reset# %s\n"
|
||||
"#444444 Accel.# %s\n",
|
||||
dateTimeController.Day(),
|
||||
static_cast<uint8_t>(dateTimeController.Month()),
|
||||
dateTimeController.Year(),
|
||||
@@ -154,12 +160,12 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
|
||||
uptimeMinutes,
|
||||
uptimeSeconds,
|
||||
batteryPercent,
|
||||
batteryVoltageBytes[1],
|
||||
batteryVoltageBytes[0],
|
||||
batteryController.Voltage(),
|
||||
brightnessController.ToString(),
|
||||
resetReason);
|
||||
resetReason,
|
||||
ToString(motionController.DeviceType()));
|
||||
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
return std::unique_ptr<Screen>(new Screens::Label(1, 4, app, label));
|
||||
return std::make_unique<Screens::Label>(1, 5, app, label);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
|
||||
@@ -173,59 +179,83 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
|
||||
"#444444 BLE MAC#\n"
|
||||
" %02x:%02x:%02x:%02x:%02x:%02x"
|
||||
"\n"
|
||||
"#444444 Memory#\n"
|
||||
"#444444 LVGL Memory#\n"
|
||||
" #444444 used# %d (%d%%)\n"
|
||||
" #444444 max used# %lu\n"
|
||||
" #444444 frag# %d%%\n"
|
||||
" #444444 free# %d"
|
||||
"\n"
|
||||
"#444444 Steps# %li",
|
||||
"#444444 Steps# %i",
|
||||
bleAddr[5],
|
||||
bleAddr[4],
|
||||
bleAddr[3],
|
||||
bleAddr[2],
|
||||
bleAddr[1],
|
||||
bleAddr[0],
|
||||
(int) mon.total_size - mon.free_size,
|
||||
static_cast<int>(mon.total_size - mon.free_size),
|
||||
mon.used_pct,
|
||||
mon.max_used,
|
||||
mon.frag_pct,
|
||||
(int) mon.free_biggest_size,
|
||||
static_cast<int>(mon.free_biggest_size),
|
||||
0);
|
||||
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
return std::unique_ptr<Screen>(new Screens::Label(2, 5, app, label));
|
||||
return std::make_unique<Screens::Label>(2, 5, app, label);
|
||||
}
|
||||
|
||||
bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
|
||||
bool SystemInfo::sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
|
||||
return lhs.xTaskNumber < rhs.xTaskNumber;
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
|
||||
TaskStatus_t tasksStatus[7];
|
||||
lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
|
||||
lv_table_set_col_cnt(infoTask, 3);
|
||||
lv_table_set_col_cnt(infoTask, 4);
|
||||
lv_table_set_row_cnt(infoTask, 8);
|
||||
lv_obj_set_pos(infoTask, 10, 10);
|
||||
lv_obj_set_pos(infoTask, 0, 10);
|
||||
|
||||
lv_table_set_cell_value(infoTask, 0, 0, "#");
|
||||
lv_table_set_col_width(infoTask, 0, 50);
|
||||
lv_table_set_cell_value(infoTask, 0, 1, "Task");
|
||||
lv_table_set_col_width(infoTask, 1, 80);
|
||||
lv_table_set_cell_value(infoTask, 0, 2, "Free");
|
||||
lv_table_set_col_width(infoTask, 2, 90);
|
||||
lv_table_set_col_width(infoTask, 0, 30);
|
||||
lv_table_set_cell_value(infoTask, 0, 1, "S"); // State
|
||||
lv_table_set_col_width(infoTask, 1, 30);
|
||||
lv_table_set_cell_value(infoTask, 0, 2, "Task");
|
||||
lv_table_set_col_width(infoTask, 2, 80);
|
||||
lv_table_set_cell_value(infoTask, 0, 3, "Free");
|
||||
lv_table_set_col_width(infoTask, 3, 90);
|
||||
|
||||
auto nb = uxTaskGetSystemState(tasksStatus, 7, nullptr);
|
||||
std::sort(tasksStatus, tasksStatus + nb, sortById);
|
||||
for (uint8_t i = 0; i < nb; i++) {
|
||||
|
||||
lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
|
||||
lv_table_set_cell_value(infoTask, i + 1, 1, tasksStatus[i].pcTaskName);
|
||||
char state[2] = {0};
|
||||
switch (tasksStatus[i].eCurrentState) {
|
||||
case eReady:
|
||||
case eRunning:
|
||||
state[0] = 'R';
|
||||
break;
|
||||
case eBlocked:
|
||||
state[0] = 'B';
|
||||
break;
|
||||
case eSuspended:
|
||||
state[0] = 'S';
|
||||
break;
|
||||
case eDeleted:
|
||||
state[0] = 'D';
|
||||
break;
|
||||
default:
|
||||
state[0] = 'I'; // Invalid
|
||||
break;
|
||||
}
|
||||
lv_table_set_cell_value(infoTask, i + 1, 1, state);
|
||||
lv_table_set_cell_value(infoTask, i + 1, 2, tasksStatus[i].pcTaskName);
|
||||
if (tasksStatus[i].usStackHighWaterMark < 20) {
|
||||
std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
|
||||
lv_table_set_cell_value(infoTask, i + 1, 2, str1.c_str());
|
||||
lv_table_set_cell_value(infoTask, i + 1, 3, str1.c_str());
|
||||
} else {
|
||||
lv_table_set_cell_value(infoTask, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
|
||||
lv_table_set_cell_value(infoTask, i + 1, 3, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
|
||||
}
|
||||
}
|
||||
return std::unique_ptr<Screen>(new Screens::Label(3, 5, app, infoTask));
|
||||
return std::make_unique<Screens::Label>(3, 5, app, infoTask);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> SystemInfo::CreateScreen5() {
|
||||
@@ -241,5 +271,5 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen5() {
|
||||
"#FFFF00 JF002/InfiniTime#");
|
||||
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
return std::unique_ptr<Screen>(new Screens::Label(4, 5, app, label));
|
||||
return std::make_unique<Screens::Label>(4, 5, app, label);
|
||||
}
|
||||
|
@@ -27,22 +27,24 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::Battery& batteryController,
|
||||
Pinetime::Controllers::BrightnessController& brightnessController,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
Pinetime::Drivers::WatchdogView& watchdog);
|
||||
Pinetime::Drivers::WatchdogView& watchdog,
|
||||
Pinetime::Controllers::MotionController& motionController);
|
||||
~SystemInfo() override;
|
||||
bool Refresh() override;
|
||||
bool OnButtonPushed() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
private:
|
||||
bool running = true;
|
||||
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
Pinetime::Controllers::BrightnessController& brightnessController;
|
||||
Pinetime::Controllers::Ble& bleController;
|
||||
Pinetime::Drivers::WatchdogView& watchdog;
|
||||
Pinetime::Controllers::MotionController& motionController;
|
||||
|
||||
ScreenList<5> screens;
|
||||
|
||||
static bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs);
|
||||
|
||||
std::unique_ptr<Screen> CreateScreen1();
|
||||
std::unique_ptr<Screen> CreateScreen2();
|
||||
std::unique_ptr<Screen> CreateScreen3();
|
||||
@@ -51,4 +53,4 @@ namespace Pinetime {
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,15 +6,17 @@ using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static void lv_update_task(struct _lv_task_t* task) {
|
||||
auto user_data = static_cast<Tile*>(task->user_data);
|
||||
auto* user_data = static_cast<Tile*>(task->user_data);
|
||||
user_data->UpdateScreen();
|
||||
}
|
||||
|
||||
static void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
if (event != LV_EVENT_VALUE_CHANGED) return;
|
||||
|
||||
Tile* screen = static_cast<Tile*>(obj->user_data);
|
||||
uint32_t* eventDataPtr = (uint32_t*) lv_event_get_data();
|
||||
auto* eventDataPtr = (uint32_t*) lv_event_get_data();
|
||||
uint32_t eventData = *eventDataPtr;
|
||||
screen->OnObjectEvent(obj, event, eventData);
|
||||
screen->OnValueChangedEvent(obj, eventData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +109,7 @@ Tile::Tile(uint8_t screenID,
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text_static(backgroundLabel, "");
|
||||
|
||||
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this);
|
||||
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this);
|
||||
}
|
||||
|
||||
Tile::~Tile() {
|
||||
@@ -124,9 +126,9 @@ bool Tile::Refresh() {
|
||||
return running;
|
||||
}
|
||||
|
||||
void Tile::OnObjectEvent(lv_obj_t* obj, lv_event_t event, uint32_t buttonId) {
|
||||
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||
app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up);
|
||||
running = false;
|
||||
}
|
||||
void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) {
|
||||
if(obj != btnm1) return;
|
||||
|
||||
app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up);
|
||||
running = false;
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ namespace Pinetime {
|
||||
|
||||
bool Refresh() override;
|
||||
void UpdateScreen();
|
||||
void OnObjectEvent(lv_obj_t* obj, lv_event_t event, uint32_t buttonId);
|
||||
void OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId);
|
||||
|
||||
private:
|
||||
Pinetime::Controllers::Battery& batteryController;
|
||||
|
173
src/displayapp/screens/Timer.cpp
Normal file
173
src/displayapp/screens/Timer.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "Timer.h"
|
||||
|
||||
#include "Screen.h"
|
||||
#include "Symbols.h"
|
||||
#include "lvgl/lvgl.h"
|
||||
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
|
||||
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
Timer* screen = static_cast<Timer*>(obj->user_data);
|
||||
screen->OnButtonEvent(obj, event);
|
||||
}
|
||||
|
||||
void Timer::createButtons() {
|
||||
btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnMinutesUp->user_data = this;
|
||||
lv_obj_set_event_cb(btnMinutesUp, btnEventHandler);
|
||||
lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -80);
|
||||
lv_obj_set_height(btnMinutesUp, 40);
|
||||
lv_obj_set_width(btnMinutesUp, 60);
|
||||
txtMUp = lv_label_create(btnMinutesUp, nullptr);
|
||||
lv_label_set_text(txtMUp, "+");
|
||||
|
||||
btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnMinutesDown->user_data = this;
|
||||
lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
|
||||
lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, +40);
|
||||
lv_obj_set_height(btnMinutesDown, 40);
|
||||
lv_obj_set_width(btnMinutesDown, 60);
|
||||
txtMDown = lv_label_create(btnMinutesDown, nullptr);
|
||||
lv_label_set_text(txtMDown, "-");
|
||||
|
||||
btnSecondsUp = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSecondsUp->user_data = this;
|
||||
lv_obj_set_event_cb(btnSecondsUp, btnEventHandler);
|
||||
lv_obj_align(btnSecondsUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 10, -80);
|
||||
lv_obj_set_height(btnSecondsUp, 40);
|
||||
lv_obj_set_width(btnSecondsUp, 60);
|
||||
txtSUp = lv_label_create(btnSecondsUp, nullptr);
|
||||
lv_label_set_text(txtSUp, "+");
|
||||
|
||||
btnSecondsDown = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnSecondsDown->user_data = this;
|
||||
lv_obj_set_event_cb(btnSecondsDown, btnEventHandler);
|
||||
lv_obj_align(btnSecondsDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 10, +40);
|
||||
lv_obj_set_height(btnSecondsDown, 40);
|
||||
lv_obj_set_width(btnSecondsDown, 60);
|
||||
txtSDown = lv_label_create(btnSecondsDown, nullptr);
|
||||
lv_label_set_text(txtSDown, "-");
|
||||
|
||||
}
|
||||
|
||||
|
||||
Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController)
|
||||
: Screen(app),
|
||||
running{true},
|
||||
timerController{timerController} {
|
||||
|
||||
time = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
|
||||
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
|
||||
lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60);
|
||||
|
||||
lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20);
|
||||
|
||||
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnPlayPause->user_data = this;
|
||||
lv_obj_set_event_cb(btnPlayPause, btnEventHandler);
|
||||
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);
|
||||
if (timerController.IsRunning()) {
|
||||
lv_label_set_text(txtPlayPause, Symbols::pause);
|
||||
} else {
|
||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||
createButtons();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
|
||||
}
|
||||
|
||||
bool Timer::Refresh() {
|
||||
if (timerController.IsRunning()) {
|
||||
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
|
||||
lv_label_set_text_fmt(time, "%02lu:%02lu", seconds / 60, seconds % 60);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
if (obj == btnPlayPause) {
|
||||
if (timerController.IsRunning()) {
|
||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
|
||||
minutesToSet = seconds / 60;
|
||||
secondsToSet = seconds % 60;
|
||||
timerController.StopTimer();
|
||||
createButtons();
|
||||
|
||||
} else if (secondsToSet + minutesToSet > 0) {
|
||||
lv_label_set_text(txtPlayPause, Symbols::pause);
|
||||
timerController.StartTimer((secondsToSet + minutesToSet * 60) * 1000);
|
||||
|
||||
lv_obj_del(btnSecondsDown);
|
||||
btnSecondsDown = nullptr;
|
||||
lv_obj_del(btnSecondsUp);
|
||||
btnSecondsUp = nullptr;
|
||||
lv_obj_del(btnMinutesDown);
|
||||
btnMinutesDown = nullptr;
|
||||
lv_obj_del(btnMinutesUp);
|
||||
btnMinutesUp = nullptr;
|
||||
|
||||
}
|
||||
} else {
|
||||
if (!timerController.IsRunning()) {
|
||||
if (obj == btnMinutesUp) {
|
||||
if (minutesToSet >= 59) {
|
||||
minutesToSet = 0;
|
||||
} else {
|
||||
minutesToSet++;
|
||||
}
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
|
||||
|
||||
} else if (obj == btnMinutesDown) {
|
||||
if (minutesToSet == 0) {
|
||||
minutesToSet = 59;
|
||||
} else {
|
||||
minutesToSet--;
|
||||
}
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
|
||||
|
||||
} else if (obj == btnSecondsUp) {
|
||||
if (secondsToSet >= 59) {
|
||||
secondsToSet = 0;
|
||||
} else {
|
||||
secondsToSet++;
|
||||
}
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
|
||||
|
||||
} else if (obj == btnSecondsDown) {
|
||||
if (secondsToSet == 0) {
|
||||
secondsToSet = 59;
|
||||
} else {
|
||||
secondsToSet--;
|
||||
}
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", minutesToSet, secondsToSet);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Timer::setDone() {
|
||||
lv_label_set_text(time, "00:00");
|
||||
lv_label_set_text(txtPlayPause, Symbols::play);
|
||||
secondsToSet = 0;
|
||||
minutesToSet = 0;
|
||||
createButtons();
|
||||
}
|
42
src/displayapp/screens/Timer.h
Normal file
42
src/displayapp/screens/Timer.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "../LittleVgl.h"
|
||||
|
||||
#include "components/timer/TimerController.h"
|
||||
|
||||
namespace Pinetime::Applications::Screens {
|
||||
|
||||
|
||||
class Timer : public Screen {
|
||||
public:
|
||||
|
||||
enum class Modes {
|
||||
Normal, Done
|
||||
};
|
||||
|
||||
Timer(DisplayApp* app, Controllers::TimerController& timerController);
|
||||
|
||||
~Timer() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
void setDone();
|
||||
|
||||
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
|
||||
|
||||
private:
|
||||
|
||||
bool running;
|
||||
uint8_t secondsToSet = 0;
|
||||
uint8_t minutesToSet = 0;
|
||||
Controllers::TimerController& timerController;
|
||||
|
||||
void createButtons();
|
||||
|
||||
lv_obj_t* time, * msecTime, * btnPlayPause, * txtPlayPause, * btnMinutesUp, * btnMinutesDown, * btnSecondsUp, * btnSecondsDown, * txtMUp,
|
||||
* txtMDown, * txtSUp, * txtSDown;
|
||||
};
|
||||
}
|
@@ -5,39 +5,56 @@
|
||||
#include "Symbols.h"
|
||||
#include "NotificationIcon.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
LV_IMG_DECLARE(bg_clock);
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
#define HOUR_LENGTH 70
|
||||
#define MINUTE_LENGTH 90
|
||||
#define SECOND_LENGTH 110
|
||||
#define PI 3.14159265358979323846
|
||||
namespace {
|
||||
|
||||
// ##
|
||||
static int16_t coordinate_x_relocate(int16_t x) {
|
||||
return ((x) + LV_HOR_RES / 2);
|
||||
constexpr auto HOUR_LENGTH = 70;
|
||||
constexpr auto MINUTE_LENGTH = 90;
|
||||
constexpr auto SECOND_LENGTH = 110;
|
||||
|
||||
// sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor
|
||||
const auto LV_TRIG_SCALE = _lv_trigo_sin(90);
|
||||
|
||||
int16_t cosine(int16_t angle) {
|
||||
return _lv_trigo_sin(angle + 90);
|
||||
}
|
||||
|
||||
// ##
|
||||
static int16_t coordinate_y_relocate(int16_t y) {
|
||||
return (((y) -LV_HOR_RES / 2) < 0) ? (0 - ((y) -LV_HOR_RES / 2)) : ((y) -LV_HOR_RES / 2);
|
||||
int16_t sine(int16_t angle) {
|
||||
return _lv_trigo_sin(angle);
|
||||
}
|
||||
|
||||
int16_t coordinate_x_relocate(int16_t x) {
|
||||
return (x + LV_HOR_RES / 2);
|
||||
}
|
||||
|
||||
int16_t coordinate_y_relocate(int16_t y) {
|
||||
return std::abs(y - LV_HOR_RES / 2);
|
||||
}
|
||||
|
||||
lv_point_t coordinate_relocate(int16_t radius, int16_t angle) {
|
||||
return lv_point_t{
|
||||
.x = coordinate_x_relocate(radius * static_cast<int32_t>(sine(angle)) / LV_TRIG_SCALE),
|
||||
.y = coordinate_y_relocate(radius * static_cast<int32_t>(cosine(angle)) / LV_TRIG_SCALE)
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController)
|
||||
: Screen(app),
|
||||
currentDateTime {{}},
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
bleController {bleController},
|
||||
notificatioManager {notificatioManager},
|
||||
notificationManager {notificationManager},
|
||||
settingsController {settingsController} {
|
||||
settingsController.SetClockFace(1);
|
||||
|
||||
@@ -123,15 +140,12 @@ void WatchFaceAnalog::UpdateClock() {
|
||||
second = dateTimeController.Seconds();
|
||||
|
||||
if (sMinute != minute) {
|
||||
minute_point[0].x = coordinate_x_relocate(30 * sin(minute * 6 * PI / 180));
|
||||
minute_point[0].y = coordinate_y_relocate(30 * cos(minute * 6 * PI / 180));
|
||||
minute_point[1].x = coordinate_x_relocate(MINUTE_LENGTH * sin(minute * 6 * PI / 180));
|
||||
minute_point[1].y = coordinate_y_relocate(MINUTE_LENGTH * cos(minute * 6 * PI / 180));
|
||||
auto const angle = minute * 6;
|
||||
minute_point[0] = coordinate_relocate(30, angle);
|
||||
minute_point[1] = coordinate_relocate(MINUTE_LENGTH, angle);
|
||||
|
||||
minute_point_trace[0].x = coordinate_x_relocate(5 * sin(minute * 6 * PI / 180));
|
||||
minute_point_trace[0].y = coordinate_y_relocate(5 * cos(minute * 6 * PI / 180));
|
||||
minute_point_trace[1].x = coordinate_x_relocate(31 * sin(minute * 6 * PI / 180));
|
||||
minute_point_trace[1].y = coordinate_y_relocate(31 * cos(minute * 6 * PI / 180));
|
||||
minute_point_trace[0] = coordinate_relocate(5, angle);
|
||||
minute_point_trace[1] = coordinate_relocate(31, angle);
|
||||
|
||||
lv_line_set_points(minute_body, minute_point, 2);
|
||||
lv_line_set_points(minute_body_trace, minute_point_trace, 2);
|
||||
@@ -140,15 +154,13 @@ void WatchFaceAnalog::UpdateClock() {
|
||||
if (sHour != hour || sMinute != minute) {
|
||||
sHour = hour;
|
||||
sMinute = minute;
|
||||
hour_point[0].x = coordinate_x_relocate(30 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[0].y = coordinate_y_relocate(30 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[1].x = coordinate_x_relocate(HOUR_LENGTH * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[1].y = coordinate_y_relocate(HOUR_LENGTH * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
auto const angle = (hour * 30 + minute / 2);
|
||||
|
||||
hour_point_trace[0].x = coordinate_x_relocate(5 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point_trace[0].y = coordinate_y_relocate(5 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point_trace[1].x = coordinate_x_relocate(31 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point_trace[1].y = coordinate_y_relocate(31 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[0] = coordinate_relocate(30, angle);
|
||||
hour_point[1] = coordinate_relocate(HOUR_LENGTH, angle);
|
||||
|
||||
hour_point_trace[0] = coordinate_relocate(5, angle);
|
||||
hour_point_trace[1] = coordinate_relocate(31, angle);
|
||||
|
||||
lv_line_set_points(hour_body, hour_point, 2);
|
||||
lv_line_set_points(hour_body_trace, hour_point_trace, 2);
|
||||
@@ -156,23 +168,22 @@ void WatchFaceAnalog::UpdateClock() {
|
||||
|
||||
if (sSecond != second) {
|
||||
sSecond = second;
|
||||
second_point[0].x = coordinate_x_relocate(20 * sin((180 + second * 6) * PI / 180));
|
||||
second_point[0].y = coordinate_y_relocate(20 * cos((180 + second * 6) * PI / 180));
|
||||
second_point[1].x = coordinate_x_relocate(SECOND_LENGTH * sin(second * 6 * PI / 180));
|
||||
second_point[1].y = coordinate_y_relocate(SECOND_LENGTH * cos(second * 6 * PI / 180));
|
||||
auto const angle = second * 6;
|
||||
|
||||
second_point[0] = coordinate_relocate(-20, angle);
|
||||
second_point[1] = coordinate_relocate(SECOND_LENGTH, angle);
|
||||
lv_line_set_points(second_body, second_point, 2);
|
||||
}
|
||||
}
|
||||
|
||||
bool WatchFaceAnalog::Refresh() {
|
||||
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
if (batteryPercentRemaining.IsUpdated()) {
|
||||
auto batteryPercent = batteryPercentRemaining.Get();
|
||||
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
|
||||
}
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
notificationState = notificationManager.AreNewNotificationsAvailable();
|
||||
|
||||
if (notificationState.IsUpdated()) {
|
||||
if (notificationState.Get() == true)
|
||||
@@ -202,4 +213,4 @@ bool WatchFaceAnalog::Refresh() {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Settings& settingsController);
|
||||
|
||||
~WatchFaceAnalog() override;
|
||||
@@ -48,7 +48,7 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
|
||||
DirtyValue<float> batteryPercentRemaining {0};
|
||||
DirtyValue<uint8_t> batteryPercentRemaining {0};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
|
||||
DirtyValue<bool> notificationState {false};
|
||||
|
||||
@@ -79,11 +79,11 @@ namespace Pinetime {
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::NotificationManager& notificationManager;
|
||||
Controllers::Settings& settingsController;
|
||||
|
||||
void UpdateClock();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ namespace Pinetime {
|
||||
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
|
||||
DirtyValue<int> batteryPercentRemaining {};
|
||||
DirtyValue<uint8_t> batteryPercentRemaining {};
|
||||
DirtyValue<bool> bleState {};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
|
||||
DirtyValue<bool> motionSensorOk {};
|
||||
|
@@ -7,12 +7,12 @@ using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
QuickSettings* screen = static_cast<QuickSettings*>(obj->user_data);
|
||||
auto* screen = static_cast<QuickSettings*>(obj->user_data);
|
||||
screen->OnButtonEvent(obj, event);
|
||||
}
|
||||
|
||||
static void lv_update_task(struct _lv_task_t* task) {
|
||||
auto user_data = static_cast<QuickSettings*>(task->user_data);
|
||||
auto* user_data = static_cast<QuickSettings*>(task->user_data);
|
||||
user_data->UpdateScreen();
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
|
||||
batteryController {batteryController},
|
||||
dateTimeController {dateTimeController},
|
||||
brightness {brightness},
|
||||
motorController{motorController},
|
||||
motorController {motorController},
|
||||
settingsController {settingsController} {
|
||||
|
||||
// Time
|
||||
@@ -110,7 +110,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text_static(backgroundLabel, "");
|
||||
|
||||
taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this);
|
||||
taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this);
|
||||
}
|
||||
|
||||
QuickSettings::~QuickSettings() {
|
||||
@@ -154,17 +154,6 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
|
||||
}
|
||||
}
|
||||
|
||||
bool QuickSettings::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
switch (event) {
|
||||
case Pinetime::Applications::TouchEvents::SwipeLeft:
|
||||
running = false;
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool QuickSettings::Refresh() {
|
||||
return running;
|
||||
}
|
||||
|
@@ -29,7 +29,6 @@ namespace Pinetime {
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
||||
|
||||
void UpdateScreen();
|
||||
|
@@ -45,7 +45,7 @@ SettingSteps::SettingSteps(
|
||||
|
||||
stepValue = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
|
||||
lv_label_set_text_fmt(stepValue,"%i", settingsController.GetStepsGoal());
|
||||
lv_label_set_text_fmt(stepValue, "%lu", settingsController.GetStepsGoal());
|
||||
lv_label_set_align(stepValue, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
|
||||
|
||||
@@ -81,7 +81,7 @@ void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) {
|
||||
value += 1000;
|
||||
if ( value <= 500000 ) {
|
||||
settingsController.SetStepsGoal(value);
|
||||
lv_label_set_text_fmt(stepValue,"%i", settingsController.GetStepsGoal());
|
||||
lv_label_set_text_fmt(stepValue, "%lu", settingsController.GetStepsGoal());
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ void SettingSteps::UpdateSelected(lv_obj_t *object, lv_event_t event) {
|
||||
value -= 1000;
|
||||
if ( value >= 1000 ) {
|
||||
settingsController.SetStepsGoal(value);
|
||||
lv_label_set_text_fmt(stepValue,"%i", settingsController.GetStepsGoal());
|
||||
lv_label_set_text_fmt(stepValue, "%lu", settingsController.GetStepsGoal());
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ namespace {
|
||||
|
||||
SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
|
||||
: Screen(app), settingsController {settingsController} {
|
||||
|
||||
ignoringEvents = false;
|
||||
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);
|
||||
@@ -36,24 +36,16 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
|
||||
|
||||
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_text_static(icon, Symbols::eye);
|
||||
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], " None");
|
||||
cbOption[optionsTotal]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::None) {
|
||||
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||
}
|
||||
optionsTotal++;
|
||||
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
|
||||
lv_checkbox_set_text_static(cbOption[optionsTotal], " Single Tap");
|
||||
cbOption[optionsTotal]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::SingleTap) {
|
||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) {
|
||||
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||
}
|
||||
optionsTotal++;
|
||||
@@ -61,7 +53,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
|
||||
lv_checkbox_set_text_static(cbOption[optionsTotal], " Double Tap");
|
||||
cbOption[optionsTotal]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) {
|
||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
|
||||
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||
}
|
||||
optionsTotal++;
|
||||
@@ -69,7 +61,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
|
||||
lv_checkbox_set_text_static(cbOption[optionsTotal], " Raise Wrist");
|
||||
cbOption[optionsTotal]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||
if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) {
|
||||
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) {
|
||||
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||
}
|
||||
optionsTotal++;
|
||||
@@ -85,27 +77,31 @@ bool SettingWakeUp::Refresh() {
|
||||
}
|
||||
|
||||
void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||
for (int i = 0; i < optionsTotal; i++) {
|
||||
if (object == cbOption[i]) {
|
||||
lv_checkbox_set_checked(cbOption[i], true);
|
||||
using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode;
|
||||
if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) {
|
||||
ignoringEvents = true;
|
||||
|
||||
if (i == 0) {
|
||||
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::None);
|
||||
};
|
||||
if (i == 1) {
|
||||
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::SingleTap);
|
||||
};
|
||||
if (i == 2) {
|
||||
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap);
|
||||
};
|
||||
if (i == 3) {
|
||||
settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist);
|
||||
};
|
||||
|
||||
} else {
|
||||
lv_checkbox_set_checked(cbOption[i], false);
|
||||
// Find the index of the checkbox that triggered the event
|
||||
int index = 0;
|
||||
for (; index < optionsTotal; ++index) {
|
||||
if (cbOption[index] == object) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle needed wakeup mode
|
||||
auto mode = static_cast<WakeUpMode>(index);
|
||||
auto currentState = settingsController.isWakeUpModeOn(mode);
|
||||
settingsController.setWakeUpMode(mode, !currentState);
|
||||
|
||||
// Update checkbox according to current wakeup modes.
|
||||
// This is needed because we can have extra logic when setting or unsetting wakeup modes,
|
||||
// for example, when setting SingleTap, DoubleTap is unset and vice versa.
|
||||
auto modes = settingsController.getWakeUpModes();
|
||||
for (int i = 0; i < optionsTotal; ++i) {
|
||||
lv_checkbox_set_checked(cbOption[i], modes[i]);
|
||||
}
|
||||
|
||||
ignoringEvents = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,11 @@ namespace Pinetime {
|
||||
Controllers::Settings& settingsController;
|
||||
uint8_t optionsTotal;
|
||||
lv_obj_t* cbOption[4];
|
||||
// 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.
|
||||
// This variable is used as a mutex to prevent that.
|
||||
bool ignoringEvents;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pine
|
||||
|
||||
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_text_static(icon, Symbols::home);
|
||||
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
||||
|
||||
@@ -58,6 +58,15 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pine
|
||||
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||
}
|
||||
|
||||
optionsTotal++;
|
||||
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
|
||||
lv_checkbox_set_text_static(cbOption[optionsTotal], " PineTimeStyle");
|
||||
cbOption[optionsTotal]->user_data = this;
|
||||
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||
if (settingsController.GetClockFace() == 2) {
|
||||
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||
}
|
||||
|
||||
optionsTotal++;
|
||||
}
|
||||
|
||||
@@ -81,4 +90,4 @@ void SettingWatchFace::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -41,12 +41,12 @@ std::unique_ptr<Screen> Settings::CreateScreen1() {
|
||||
|
||||
std::array<Screens::List::Applications, 4> applications {{
|
||||
{Symbols::sun, "Display", Apps::SettingDisplay},
|
||||
{Symbols::clock, "Wake Up", Apps::SettingWakeUp},
|
||||
{Symbols::eye, "Wake Up", Apps::SettingWakeUp},
|
||||
{Symbols::clock, "Time format", Apps::SettingTimeFormat},
|
||||
{Symbols::clock, "Watch face", Apps::SettingWatchFace},
|
||||
{Symbols::home, "Watch face", Apps::SettingWatchFace},
|
||||
}};
|
||||
|
||||
return std::unique_ptr<Screen>(new Screens::List(0, 2, app, settingsController, applications));
|
||||
return std::make_unique<Screens::List>(0, 2, app, settingsController, applications);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Settings::CreateScreen2() {
|
||||
@@ -58,5 +58,5 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
|
||||
{Symbols::list, "About", Apps::SysInfo},
|
||||
}};
|
||||
|
||||
return std::unique_ptr<Screen>(new Screens::List(1, 2, app, settingsController, applications));
|
||||
return std::make_unique<Screens::List>(1, 2, app, settingsController, applications);
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ namespace Pinetime {
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
|
||||
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
|
||||
|
||||
private:
|
||||
|
@@ -42,6 +42,12 @@ void Bma421::Init() {
|
||||
if (ret != BMA4_OK)
|
||||
return;
|
||||
|
||||
switch(bma.chip_id) {
|
||||
case BMA423_CHIP_ID: deviceType = DeviceTypes::BMA421; break;
|
||||
case BMA425_CHIP_ID: deviceType = DeviceTypes::BMA425; break;
|
||||
default: deviceType = DeviceTypes::Unknown; break;
|
||||
}
|
||||
|
||||
ret = bma423_write_config_file(&bma);
|
||||
if (ret != BMA4_OK)
|
||||
return;
|
||||
@@ -103,8 +109,6 @@ Bma421::Values Bma421::Process() {
|
||||
uint8_t activity = 0;
|
||||
bma423_activity_output(&activity, &bma);
|
||||
|
||||
NRF_LOG_INFO("MOTION : %d - %d/%d/%d", steps, data.x, data.y, data.z);
|
||||
|
||||
// X and Y axis are swapped because of the way the sensor is mounted in the PineTime
|
||||
return {steps, data.y, data.x, data.z};
|
||||
}
|
||||
@@ -123,3 +127,6 @@ void Bma421::SoftReset() {
|
||||
nrf_delay_ms(1);
|
||||
}
|
||||
}
|
||||
Bma421::DeviceTypes Bma421::DeviceType() const {
|
||||
return deviceType;
|
||||
}
|
||||
|
@@ -6,6 +6,11 @@ namespace Pinetime {
|
||||
class TwiMaster;
|
||||
class Bma421 {
|
||||
public:
|
||||
enum class DeviceTypes : uint8_t {
|
||||
Unknown,
|
||||
BMA421,
|
||||
BMA425
|
||||
};
|
||||
struct Values {
|
||||
uint32_t steps;
|
||||
int16_t x;
|
||||
@@ -29,6 +34,7 @@ namespace Pinetime {
|
||||
void Write(uint8_t registerAddress, const uint8_t* data, size_t size);
|
||||
|
||||
bool IsOk() const;
|
||||
DeviceTypes DeviceType() const;
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
@@ -38,6 +44,7 @@ namespace Pinetime {
|
||||
struct bma4_dev bma;
|
||||
bool isOk = false;
|
||||
bool isResetOk = false;
|
||||
DeviceTypes deviceType = DeviceTypes::Unknown;
|
||||
};
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user