diff options
Diffstat (limited to 'src')
137 files changed, 1357 insertions, 1179 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce365dd1..95846a9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -407,6 +407,7 @@ list(APPEND SOURCE_FILES displayapp/Colors.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp + displayapp/widgets/DotIndicator.cpp displayapp/widgets/StatusIcons.cpp ## Settings @@ -417,6 +418,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingWakeUp.cpp displayapp/screens/settings/SettingDisplay.cpp displayapp/screens/settings/SettingSteps.cpp + displayapp/screens/settings/SettingSetDateTime.cpp displayapp/screens/settings/SettingSetDate.cpp displayapp/screens/settings/SettingSetTime.cpp displayapp/screens/settings/SettingChimes.cpp @@ -440,7 +442,6 @@ list(APPEND SOURCE_FILES drivers/SpiMaster.cpp drivers/Spi.cpp drivers/Watchdog.cpp - drivers/DebugPins.cpp drivers/InternalFlash.cpp drivers/Hrs3300.cpp drivers/Bma421.cpp @@ -507,7 +508,6 @@ list(APPEND RECOVERY_SOURCE_FILES drivers/SpiMaster.cpp drivers/Spi.cpp drivers/Watchdog.cpp - drivers/DebugPins.cpp drivers/InternalFlash.cpp drivers/Hrs3300.cpp drivers/Bma421.cpp @@ -616,13 +616,13 @@ set(INCLUDE_FILES displayapp/Colors.h displayapp/widgets/Counter.h displayapp/widgets/PageIndicator.h + displayapp/widgets/DotIndicator.h displayapp/widgets/StatusIcons.h drivers/St7789.h drivers/SpiNorFlash.h drivers/SpiMaster.h drivers/Spi.h drivers/Watchdog.h - drivers/DebugPins.h drivers/InternalFlash.h drivers/Hrs3300.h drivers/PinMap.h @@ -686,6 +686,8 @@ include_directories( ${CMAKE_BINARY_DIR}/src # include generated files like Version.h . ../ +) +include_directories(SYSTEM libs/ FreeRTOS/ libs/date/include @@ -778,7 +780,12 @@ link_directories( ) -set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -ftree-vrp -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -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) +set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -ftree-vrp -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin -fshort-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fstack-usage -fno-exceptions -fno-non-call-exceptions) +set(WARNING_FLAGS -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -Wreturn-type -Werror=return-type) +set(DEBUG_FLAGS -Og -g3) +set(RELEASE_FLAGS -Os) +set(CXX_FLAGS -fno-rtti) +set(ASM_FLAGS -x assembler-with-cpp) add_definitions(-DCONFIG_GPIO_AS_PINRESET) add_definitions(-DNIMBLE_CFG_CONTROLLER) add_definitions(-DOS_CPUTIME_FREQ) @@ -843,11 +850,11 @@ endif() add_subdirectory(displayapp/fonts) target_compile_options(infinitime_fonts PUBLIC - $<$<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> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # NRF SDK @@ -855,11 +862,12 @@ 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} -Wno-expansion-to-defined -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3 -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> + -O3 ) # NimBLE @@ -867,11 +875,11 @@ 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} -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> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # lvgl @@ -879,11 +887,11 @@ 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} -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> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # QCBOR @@ -900,9 +908,11 @@ target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_UNCOMMON_TAGS) target_compile_definitions(QCBOR PUBLIC USEFULBUF_CONFIG_LITTLE_ENDIAN) set_target_properties(QCBOR PROPERTIES LINKER_LANGUAGE C) target_compile_options(QCBOR PRIVATE - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> + -O3 ) # LITTLEFS_SRC @@ -910,11 +920,11 @@ 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> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # Build autonomous binary (without support for bootloader) @@ -925,11 +935,12 @@ 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 littlefs QCBOR infinitime_fonts) target_compile_options(${EXECUTABLE_NAME} PUBLIC - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_NAME} PROPERTIES @@ -959,11 +970,12 @@ add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES}) target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs QCBOR infinitime_fonts) 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} -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> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES @@ -1001,11 +1013,12 @@ target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs QCBOR 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} -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> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES @@ -1032,11 +1045,12 @@ target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlef 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} -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> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES @@ -1070,11 +1084,12 @@ add_executable(${EXECUTABLE_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE_FILES}) target_link_libraries(${EXECUTABLE_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts) 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} -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> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) target_include_directories(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src> @@ -1104,11 +1119,12 @@ add_executable(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE target_link_libraries(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts) 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} -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> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) target_include_directories(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src> diff --git a/src/StaticStack.h b/src/StaticStack.h new file mode 100644 index 00000000..64886604 --- /dev/null +++ b/src/StaticStack.h @@ -0,0 +1,38 @@ +#include <array> +#include <cstddef> + +template <typename T, size_t N> class StaticStack { +public: + T Pop(); + void Push(T element); + void Reset(); + T Top(); + +private: + std::array<T, N> elementArray; + // Number of elements in stack, points to the next empty slot + size_t stackPointer = 0; +}; + +// Returns random data when popping from empty array. +template <typename T, size_t N> T StaticStack<T, N>::Pop() { + if (stackPointer > 0) { + stackPointer--; + } + return elementArray[stackPointer]; +} + +template <typename T, size_t N> void StaticStack<T, N>::Push(T element) { + if (stackPointer < elementArray.size()) { + elementArray[stackPointer] = element; + stackPointer++; + } +} + +template <typename T, size_t N> void StaticStack<T, N>::Reset() { + stackPointer = 0; +} + +template <typename T, size_t N> T StaticStack<T, N>::Top() { + return elementArray[stackPointer - 1]; +} diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp index d97e1cff..88f65d9a 100644 --- a/src/components/alarm/AlarmController.cpp +++ b/src/components/alarm/AlarmController.cpp @@ -28,7 +28,7 @@ AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : da namespace { void SetOffAlarm(TimerHandle_t xTimer) { - auto controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer)); + auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer)); controller->SetOffAlarmNow(); } } diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h index 91f60f5a..8ac0de9a 100644 --- a/src/components/alarm/AlarmController.h +++ b/src/components/alarm/AlarmController.h @@ -26,6 +26,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class AlarmController { public: @@ -40,18 +41,23 @@ namespace Pinetime { void StopAlerting(); enum class AlarmState { Not_Set, Set, Alerting }; enum class RecurType { None, Daily, Weekdays }; + uint8_t Hours() const { return hours; } + uint8_t Minutes() const { return minutes; } + AlarmState State() const { return state; } + RecurType Recurrence() const { return recurrence; } + void SetRecurrence(RecurType recurType) { recurrence = recurType; } diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index 300d0978..4d860490 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -1,4 +1,5 @@ #include "components/battery/BatteryController.h" +#include "components/utility/LinearApproximation.h" #include "drivers/PinMap.h" #include <hal/nrf_gpio.h> #include <nrfx_saadc.h> @@ -15,8 +16,8 @@ Battery::Battery() { } void Battery::ReadPowerState() { - isCharging = !nrf_gpio_pin_read(PinMap::Charging); - isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent); + isCharging = (nrf_gpio_pin_read(PinMap::Charging) == 0); + isPowerPresent = (nrf_gpio_pin_read(PinMap::PowerPresent) == 0); if (isPowerPresent && !isCharging) { isFull = true; @@ -60,8 +61,8 @@ void Battery::SaadcInit() { } void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { - 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 ) + static const Utility::LinearApproximation<uint16_t, uint8_t, 6> approx { + {{{3500, 0}, {3616, 3}, {3723, 22}, {3776, 48}, {3979, 79}, {4180, 100}}}}; if (p_event->type == NRFX_SAADC_EVT_DONE) { @@ -74,19 +75,26 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024; - uint8_t newPercent; - if (isFull) { - newPercent = 100; - } else if (voltage < battery_min) { - newPercent = 0; - } else { - newPercent = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100); + uint8_t newPercent = 100; + if (!isFull) { + // max. voltage while charging is higher than when discharging + newPercent = std::min(approx.GetValue(voltage), isCharging ? uint8_t {99} : uint8_t {100}); + } + + if (isPowerPresent) { + batteryLowNotified = false; } if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) { firstMeasurement = false; percentRemaining = newPercent; systemTask->PushMessage(System::Messages::BatteryPercentageUpdated); + + // warn about low battery when not charging and below threshold + if (BatteryIsLow() && !isPowerPresent && !batteryLowNotified) { + systemTask->PushMessage(System::Messages::LowBattery); + batteryLowNotified = true; + } } nrfx_saadc_uninit(); diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 5a7394c4..b47b77cc 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -18,6 +18,10 @@ namespace Pinetime { return percentRemaining; } + bool BatteryIsLow() const { + return percentRemaining <= lowBatteryThreshold; + } + uint16_t Voltage() const { return voltage; } @@ -39,6 +43,7 @@ namespace Pinetime { static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7; uint16_t voltage = 0; uint8_t percentRemaining = 0; + bool batteryLowNotified = false; bool isFull = false; bool isCharging = false; @@ -50,6 +55,8 @@ namespace Pinetime { void SaadcEventHandler(nrfx_saadc_evt_t const* p_event); static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); + static constexpr uint8_t lowBatteryThreshold {15}; + bool isReading = false; Pinetime::System::SystemTask* systemTask = nullptr; diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp index 095fdef6..e3bc9242 100644 --- a/src/components/ble/AlertNotificationClient.cpp +++ b/src/components/ble/AlertNotificationClient.cpp @@ -35,9 +35,9 @@ namespace { return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc); } - int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) { + int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* /*attr*/, void* arg) { auto client = static_cast<AlertNotificationClient*>(arg); - return client->OnNewAlertSubcribe(conn_handle, error, attr); + return client->OnNewAlertSubcribe(conn_handle, error); } } @@ -107,7 +107,7 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection return 0; } -int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) { +int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error) { if (error->status == 0) { NRF_LOG_INFO("ANS New alert subscribe OK"); } else { diff --git a/src/components/ble/AlertNotificationClient.h b/src/components/ble/AlertNotificationClient.h index 2d6a3873..b038f0d8 100644 --- a/src/components/ble/AlertNotificationClient.h +++ b/src/components/ble/AlertNotificationClient.h @@ -25,7 +25,7 @@ namespace Pinetime { bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service); int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); - int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute); + int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error); int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error* error, uint16_t characteristicValueHandle, diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp index 04819122..d9f28698 100644 --- a/src/components/ble/AlertNotificationService.cpp +++ b/src/components/ble/AlertNotificationService.cpp @@ -11,9 +11,9 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid; constexpr ble_uuid16_t AlertNotificationService::ansCharUuid; constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid; -int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int AlertNotificationCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto anService = static_cast<AlertNotificationService*>(arg); - return anService->OnAlert(conn_handle, attr_handle, ctxt); + return anService->OnAlert(ctxt); } void AlertNotificationService::Init() { @@ -44,7 +44,7 @@ AlertNotificationService::AlertNotificationService(System::SystemTask& systemTas notificationManager {notificationManager} { } -int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int AlertNotificationService::OnAlert(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { constexpr size_t stringTerminatorSize = 1; // end of string '\0' constexpr size_t headerSize = 3; diff --git a/src/components/ble/AlertNotificationService.h b/src/components/ble/AlertNotificationService.h index 5c7d428c..4b3c6385 100644 --- a/src/components/ble/AlertNotificationService.h +++ b/src/components/ble/AlertNotificationService.h @@ -16,6 +16,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NotificationManager; @@ -24,7 +25,7 @@ namespace Pinetime { AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); void Init(); - int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnAlert(struct ble_gatt_access_ctxt* ctxt); void AcceptIncomingCall(); void RejectIncomingCall(); diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp index 9a3f86f5..db7c8566 100644 --- a/src/components/ble/BatteryInformationService.cpp +++ b/src/components/ble/BatteryInformationService.cpp @@ -7,9 +7,9 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid; constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid; -int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int BatteryInformationServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* batteryInformationService = static_cast<BatteryInformationService*>(arg); - return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt); + return batteryInformationService->OnBatteryServiceRequested(attr_handle, ctxt); } BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) @@ -38,9 +38,7 @@ void BatteryInformationService::Init() { ASSERT(res == 0); } -int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, - uint16_t attributeHandle, - ble_gatt_access_ctxt* context) { +int BatteryInformationService::OnBatteryServiceRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == batteryLevelHandle) { NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle); uint8_t batteryValue = batteryController.PercentRemaining(); @@ -49,6 +47,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand } 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); diff --git a/src/components/ble/BatteryInformationService.h b/src/components/ble/BatteryInformationService.h index c6fc52e4..7f0a89ad 100644 --- a/src/components/ble/BatteryInformationService.h +++ b/src/components/ble/BatteryInformationService.h @@ -9,14 +9,16 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class Battery; + class BatteryInformationService { public: BatteryInformationService(Controllers::Battery& batteryController); void Init(); - int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnBatteryServiceRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level); private: diff --git a/src/components/ble/BleController.h b/src/components/ble/BleController.h index 675ede2d..de0a1bc2 100644 --- a/src/components/ble/BleController.h +++ b/src/components/ble/BleController.h @@ -24,6 +24,7 @@ namespace Pinetime { void StopFirmwareUpdate(); void FirmwareUpdateTotalBytes(uint32_t totalBytes); void FirmwareUpdateCurrentBytes(uint32_t currentBytes); + void State(FirmwareUpdateStates state) { firmwareUpdateState = state; } @@ -31,12 +32,15 @@ namespace Pinetime { bool IsFirmwareUpdating() const { return isFirmwareUpdating; } + uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } + uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } + FirmwareUpdateStates State() const { return firmwareUpdateState; } @@ -44,15 +48,19 @@ namespace Pinetime { void Address(BleAddress&& addr) { address = addr; } + const BleAddress& Address() const { return address; } + void AddressType(AddressTypes t) { addressType = t; } + void SetPairingKey(uint32_t k) { pairingKey = k; } + uint32_t GetPairingKey() const { return pairingKey; } diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp index 53e98cb6..e535ae83 100644 --- a/src/components/ble/CurrentTimeClient.cpp +++ b/src/components/ble/CurrentTimeClient.cpp @@ -85,21 +85,11 @@ int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_g // TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent CtsData result; os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result); - NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", - result.year, - result.month, - result.dayofmonth, - result.hour, - result.minute, - result.second); - dateTimeController.SetTime(result.year, - result.month, - result.dayofmonth, - 0, - result.hour, - result.minute, - result.second, - nrf_rtc_counter_get(portNRF_RTC_REG)); + uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO; + + NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second); + dateTimeController + .SetTime(year, result.month, result.dayofmonth, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); } else { NRF_LOG_INFO("Error retrieving current time: %d", error->status); } diff --git a/src/components/ble/CurrentTimeClient.h b/src/components/ble/CurrentTimeClient.h index 9e48be79..0a3a8735 100644 --- a/src/components/ble/CurrentTimeClient.h +++ b/src/components/ble/CurrentTimeClient.h @@ -19,24 +19,29 @@ namespace Pinetime { bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service); int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute); + static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; } + static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; } + void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override; private: typedef struct __attribute__((packed)) { - uint16_t year; + uint8_t year_LSO; // explicit byte ordering to be independent of machine order + uint8_t year_MSO; // BLE GATT is little endian uint8_t month; uint8_t dayofmonth; uint8_t hour; uint8_t minute; uint8_t second; - uint8_t millis; - uint8_t reason; + uint8_t dayofweek; + uint8_t fractions256; // currently ignored + uint8_t reason; // currently ignored, not that any host would set it anyway } CtsData; static constexpr uint16_t ctsServiceId {0x1805}; @@ -55,4 +60,4 @@ namespace Pinetime { std::function<void(uint16_t)> onServiceDiscovered; }; } -}
\ No newline at end of file +} diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp index 8430d1bc..856bc63a 100644 --- a/src/components/ble/CurrentTimeService.cpp +++ b/src/components/ble/CurrentTimeService.cpp @@ -5,11 +5,23 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t CurrentTimeService::ctsUuid; -constexpr ble_uuid16_t CurrentTimeService::ctChrUuid; +constexpr ble_uuid16_t CurrentTimeService::ctsCtChrUuid; +constexpr ble_uuid16_t CurrentTimeService::ctsLtChrUuid; -int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int CTSCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto cts = static_cast<CurrentTimeService*>(arg); - return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt); + + return cts->OnCurrentTimeServiceAccessed(ctxt); +} + +int CurrentTimeService::OnCurrentTimeServiceAccessed(struct ble_gatt_access_ctxt* ctxt) { + switch (ble_uuid_u16(ctxt->chr->uuid)) { + case ctsCurrentTimeCharId: + return OnCurrentTimeAccessed(ctxt); + case ctsLocalTimeCharId: + return OnLocalTimeAccessed(ctxt); + } + return -1; // Unknown characteristic } void CurrentTimeService::Init() { @@ -18,45 +30,69 @@ void CurrentTimeService::Init() { ASSERT(res == 0); res = ble_gatts_add_svcs(serviceDefinition); + ASSERT(res == 0); } -int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int CurrentTimeService::OnCurrentTimeAccessed(struct ble_gatt_access_ctxt* ctxt) { NRF_LOG_INFO("Setting time..."); if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - CtsData result; - os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result); + CtsCurrentTimeData result; + int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsCurrentTimeData), &result); + if (res < 0) { + NRF_LOG_ERROR("Error reading BLE Data writing to CTS Current Time (too little data)") + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO; - NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", - result.year, - result.month, - result.dayofmonth, - result.hour, - result.minute, - result.second); + NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second); - m_dateTimeController.SetTime(result.year, - result.month, - result.dayofmonth, - 0, - result.hour, - result.minute, - result.second, - nrf_rtc_counter_get(portNRF_RTC_REG)); + m_dateTimeController + .SetTime(year, result.month, result.dayofmonth, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - CtsData currentDateTime; - currentDateTime.year = m_dateTimeController.Year(); + CtsCurrentTimeData currentDateTime; + currentDateTime.year_LSO = m_dateTimeController.Year() & 0xff; + currentDateTime.year_MSO = (m_dateTimeController.Year() >> 8) & 0xff; currentDateTime.month = static_cast<u_int8_t>(m_dateTimeController.Month()); currentDateTime.dayofmonth = m_dateTimeController.Day(); currentDateTime.hour = m_dateTimeController.Hours(); currentDateTime.minute = m_dateTimeController.Minutes(); currentDateTime.second = m_dateTimeController.Seconds(); - currentDateTime.millis = 0; + currentDateTime.fractions256 = 0; - int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData)); + int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsCurrentTimeData)); + return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + + return 0; +} + +int CurrentTimeService::OnLocalTimeAccessed(struct ble_gatt_access_ctxt* ctxt) { + NRF_LOG_INFO("Setting timezone..."); + + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + CtsLocalTimeData result; + int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsLocalTimeData), &result); + + if (res < 0) { + NRF_LOG_ERROR("Error reading BLE Data writing to CTS Local Time (too little data)") + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + NRF_LOG_INFO("Received data: %d %d", result.timezone, result.dst); + + m_dateTimeController.SetTimeZone(result.timezone, result.dst); + + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + CtsLocalTimeData currentTimezone; + currentTimezone.timezone = m_dateTimeController.TzOffset(); + currentTimezone.dst = m_dateTimeController.DstOffset(); + + int res = os_mbuf_append(ctxt->om, ¤tTimezone, sizeof(currentTimezone)); return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } @@ -64,12 +100,19 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl } CurrentTimeService::CurrentTimeService(DateTime& dateTimeController) - : characteristicDefinition {{.uuid = &ctChrUuid.u, + : characteristicDefinition { + + {.uuid = &ctsLtChrUuid.u, .access_cb = CTSCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, + {.uuid = &ctsCtChrUuid.u, + .access_cb = CTSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, - {0}}, + + {0}}, serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, diff --git a/src/components/ble/CurrentTimeService.h b/src/components/ble/CurrentTimeService.h index ca87d970..bec75a2b 100644 --- a/src/components/ble/CurrentTimeService.h +++ b/src/components/ble/CurrentTimeService.h @@ -16,29 +16,40 @@ namespace Pinetime { CurrentTimeService(DateTime& dateTimeController); void Init(); - int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCurrentTimeServiceAccessed(struct ble_gatt_access_ctxt* ctxt); + int OnCurrentTimeAccessed(struct ble_gatt_access_ctxt* ctxt); + int OnLocalTimeAccessed(struct ble_gatt_access_ctxt* ctxt); private: static constexpr uint16_t ctsId {0x1805}; - static constexpr uint16_t ctsCharId {0x2a2b}; + static constexpr uint16_t ctsCurrentTimeCharId {0x2a2b}; + static constexpr uint16_t ctsLocalTimeCharId {0x2a0f}; static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId}; - static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId}; + static constexpr ble_uuid16_t ctsCtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCurrentTimeCharId}; + static constexpr ble_uuid16_t ctsLtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsLocalTimeCharId}; - struct ble_gatt_chr_def characteristicDefinition[2]; + struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_svc_def serviceDefinition[2]; typedef struct __attribute__((packed)) { - uint16_t year; + uint8_t year_LSO; // BLE GATT is little endian + uint8_t year_MSO; uint8_t month; uint8_t dayofmonth; uint8_t hour; uint8_t minute; uint8_t second; - uint8_t millis; - uint8_t reason; - } CtsData; + uint8_t dayofweek; + uint8_t fractions256; // currently ignored + uint8_t reason; // currently ignored, not that any host would set it anyway + } CtsCurrentTimeData; + + typedef struct __attribute__((packed)) { + int8_t timezone; + int8_t dst; + } CtsLocalTimeData; DateTime& m_dateTimeController; }; diff --git a/src/components/ble/DeviceInformationService.cpp b/src/components/ble/DeviceInformationService.cpp index 0f47c90f..f0d1b5a7 100644 --- a/src/components/ble/DeviceInformationService.cpp +++ b/src/components/ble/DeviceInformationService.cpp @@ -10,9 +10,9 @@ constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid; constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid; constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid; -int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int DeviceInformationCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto deviceInformationService = static_cast<DeviceInformationService*>(arg); - return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt); + return deviceInformationService->OnDeviceInfoRequested(ctxt); } void DeviceInformationService::Init() { @@ -24,7 +24,7 @@ void DeviceInformationService::Init() { ASSERT(res == 0); } -int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int DeviceInformationService::OnDeviceInfoRequested(struct ble_gatt_access_ctxt* ctxt) { const char* str; switch (ble_uuid_u16(ctxt->chr->uuid)) { diff --git a/src/components/ble/DeviceInformationService.h b/src/components/ble/DeviceInformationService.h index a269afb4..c4babd1b 100644 --- a/src/components/ble/DeviceInformationService.h +++ b/src/components/ble/DeviceInformationService.h @@ -14,7 +14,7 @@ namespace Pinetime { DeviceInformationService(); void Init(); - int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnDeviceInfoRequested(struct ble_gatt_access_ctxt* ctxt); private: static constexpr uint16_t deviceInfoId {0x180a}; @@ -50,4 +50,4 @@ namespace Pinetime { struct ble_gatt_svc_def serviceDefinition[2]; }; } -}
\ No newline at end of file +} diff --git a/src/components/ble/DfuService.h b/src/components/ble/DfuService.h index 4708a4a6..b56911b9 100644 --- a/src/components/ble/DfuService.h +++ b/src/components/ble/DfuService.h @@ -13,9 +13,11 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Drivers { class SpiNorFlash; } + namespace Controllers { class Ble; @@ -46,10 +48,12 @@ namespace Pinetime { void OnNotificationTimer(); void Reset(); }; + class DfuImage { public: DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} { } + void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc); void Erase(); void Append(uint8_t* data, size_t size); diff --git a/src/components/ble/FSService.h b/src/components/ble/FSService.h index 828925a8..b2299623 100644 --- a/src/components/ble/FSService.h +++ b/src/components/ble/FSService.h @@ -11,8 +11,10 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class Ble; + class FSService { public: FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs); @@ -71,6 +73,7 @@ namespace Pinetime { FSState state; char filepath[maxpathlen]; // TODO ..ugh fixed filepath len int fileSize; + using ReadHeader = struct __attribute__((packed)) { commands command; uint8_t padding; @@ -89,6 +92,7 @@ namespace Pinetime { uint32_t chunklen; uint8_t chunk[]; }; + using ReadPacing = struct __attribute__((packed)) { commands command; uint8_t status; @@ -124,6 +128,7 @@ namespace Pinetime { uint32_t dataSize; uint8_t data[]; }; + using ListDirHeader = struct __attribute__((packed)) { commands command; uint8_t padding; @@ -171,6 +176,7 @@ namespace Pinetime { commands command; uint8_t status; }; + using MoveHeader = struct __attribute__((packed)) { commands command; uint8_t padding; diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp index d49a02c8..c522e67e 100644 --- a/src/components/ble/HeartRateService.cpp +++ b/src/components/ble/HeartRateService.cpp @@ -9,9 +9,9 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid; constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid; namespace { - int HeartRateServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int HeartRateServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* heartRateService = static_cast<HeartRateService*>(arg); - return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt); + return heartRateService->OnHeartRateRequested(attr_handle, ctxt); } } @@ -45,7 +45,7 @@ void HeartRateService::Init() { ASSERT(res == 0); } -int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int HeartRateService::OnHeartRateRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == heartRateMeasurementHandle) { NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle); uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value @@ -60,7 +60,7 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { if (!heartRateMeasurementNotificationEnable) return; - uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value + uint8_t buffer[2] = {0, heartRateValue}; // [0] = flags, [1] = hr value auto* om = ble_hs_mbuf_from_flat(buffer, 2); uint16_t connectionHandle = system.nimble().connHandle(); @@ -72,12 +72,12 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om); } -void HeartRateService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void HeartRateService::SubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == heartRateMeasurementHandle) heartRateMeasurementNotificationEnable = true; } -void HeartRateService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void HeartRateService::UnsubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == heartRateMeasurementHandle) heartRateMeasurementNotificationEnable = false; -}
\ No newline at end of file +} diff --git a/src/components/ble/HeartRateService.h b/src/components/ble/HeartRateService.h index 4e4a5a42..003bdbd1 100644 --- a/src/components/ble/HeartRateService.h +++ b/src/components/ble/HeartRateService.h @@ -10,17 +10,19 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class HeartRateController; + class HeartRateService { public: HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController); void Init(); - int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnHeartRateRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewHeartRateValue(uint8_t hearRateValue); - void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); - void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); + void SubscribeNotification(uint16_t attributeHandle); + void UnsubscribeNotification(uint16_t attributeHandle); private: Pinetime::System::SystemTask& system; diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp index c80b3783..b9de615a 100644 --- a/src/components/ble/ImmediateAlertService.cpp +++ b/src/components/ble/ImmediateAlertService.cpp @@ -9,9 +9,9 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid; constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid; namespace { - int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int AlertLevelCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg); - return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt); + return immediateAlertService->OnAlertLevelChanged(attr_handle, ctxt); } const char* ToString(ImmediateAlertService::Levels level) { @@ -56,7 +56,7 @@ void ImmediateAlertService::Init() { ASSERT(res == 0); } -int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int ImmediateAlertService::OnAlertLevelChanged(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == alertLevelHandle) { if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { auto alertLevel = static_cast<Levels>(context->om->om_data[0]); diff --git a/src/components/ble/ImmediateAlertService.h b/src/components/ble/ImmediateAlertService.h index 1f778acd..47a05439 100644 --- a/src/components/ble/ImmediateAlertService.h +++ b/src/components/ble/ImmediateAlertService.h @@ -9,15 +9,17 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NotificationManager; + class ImmediateAlertService { public: enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 }; ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); void Init(); - int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnAlertLevelChanged(uint16_t attributeHandle, ble_gatt_access_ctxt* context); private: Pinetime::System::SystemTask& systemTask; diff --git a/src/components/ble/MotionService.cpp b/src/components/ble/MotionService.cpp index 121ad3b0..604f22d5 100644 --- a/src/components/ble/MotionService.cpp +++ b/src/components/ble/MotionService.cpp @@ -21,9 +21,9 @@ namespace { constexpr ble_uuid128_t stepCountCharUuid {CharUuid(0x01, 0x00)}; constexpr ble_uuid128_t motionValuesCharUuid {CharUuid(0x02, 0x00)}; - int MotionServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int MotionServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* motionService = static_cast<MotionService*>(arg); - return motionService->OnStepCountRequested(conn_handle, attr_handle, ctxt); + return motionService->OnStepCountRequested(attr_handle, ctxt); } } @@ -59,7 +59,7 @@ void MotionService::Init() { ASSERT(res == 0); } -int MotionService::OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int MotionService::OnStepCountRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == stepCountHandle) { NRF_LOG_INFO("Motion-stepcount : handle = %d", stepCountHandle); uint32_t buffer = motionController.NbSteps(); @@ -90,11 +90,12 @@ void MotionService::OnNewStepCountValue(uint32_t stepCount) { ble_gattc_notify_custom(connectionHandle, stepCountHandle, om); } + void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { if (!motionValuesNoficationEnabled) return; - int16_t buffer[3] = {motionController.X(), motionController.Y(), motionController.Z()}; + int16_t buffer[3] = {x, y, z}; auto* om = ble_hs_mbuf_from_flat(buffer, 3 * sizeof(int16_t)); uint16_t connectionHandle = system.nimble().connHandle(); @@ -106,14 +107,14 @@ void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { ble_gattc_notify_custom(connectionHandle, motionValuesHandle, om); } -void MotionService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void MotionService::SubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == stepCountHandle) stepCountNoficationEnabled = true; else if (attributeHandle == motionValuesHandle) motionValuesNoficationEnabled = true; } -void MotionService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void MotionService::UnsubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == stepCountHandle) stepCountNoficationEnabled = false; else if (attributeHandle == motionValuesHandle) diff --git a/src/components/ble/MotionService.h b/src/components/ble/MotionService.h index 1b4ac0a3..1b172528 100644 --- a/src/components/ble/MotionService.h +++ b/src/components/ble/MotionService.h @@ -10,18 +10,20 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class MotionController; + class MotionService { public: MotionService(Pinetime::System::SystemTask& system, Controllers::MotionController& motionController); void Init(); - int OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnStepCountRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewStepCountValue(uint32_t stepCount); void OnNewMotionValues(int16_t x, int16_t y, int16_t z); - void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); - void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); + void SubscribeNotification(uint16_t attributeHandle); + void UnsubscribeNotification(uint16_t attributeHandle); private: Pinetime::System::SystemTask& system; diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp index fc7cef01..403c957b 100644 --- a/src/components/ble/MusicService.cpp +++ b/src/components/ble/MusicService.cpp @@ -48,8 +48,8 @@ namespace { constexpr uint8_t MaxStringSize {40}; - 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); + 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(ctxt); } } @@ -122,7 +122,7 @@ void Pinetime::Controllers::MusicService::Init() { ASSERT(res == 0); } -int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int Pinetime::Controllers::MusicService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); size_t bufferSize = notifSize; diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h index 047d0d26..6aebc3c5 100644 --- a/src/components/ble/MusicService.h +++ b/src/components/ble/MusicService.h @@ -30,6 +30,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class MusicService { public: @@ -37,7 +38,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); void event(char event); diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp index 76143686..5508d08c 100644 --- a/src/components/ble/NavigationService.cpp +++ b/src/components/ble/NavigationService.cpp @@ -39,9 +39,9 @@ namespace { constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)}; constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)}; - int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); - return navService->OnCommand(conn_handle, attr_handle, ctxt); + int NAVCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + auto* navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); + return navService->OnCommand(ctxt); } } // namespace @@ -81,7 +81,7 @@ void Pinetime::Controllers::NavigationService::Init() { ASSERT(res == 0); } -int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int Pinetime::Controllers::NavigationService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); diff --git a/src/components/ble/NavigationService.h b/src/components/ble/NavigationService.h index c0c77f35..1c1739ba 100644 --- a/src/components/ble/NavigationService.h +++ b/src/components/ble/NavigationService.h @@ -30,6 +30,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NavigationService { @@ -38,7 +39,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); std::string getFlag(); diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 52f4e4ce..912f5927 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -322,14 +322,14 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { event->subscribe.prev_indicate); if (event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) { - heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.UnsubscribeNotification(event->subscribe.attr_handle); + motionService.UnsubscribeNotification(event->subscribe.attr_handle); } else if (event->subscribe.prev_notify == 0 && event->subscribe.cur_notify == 1) { - heartRateService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.SubscribeNotification(event->subscribe.attr_handle); + motionService.SubscribeNotification(event->subscribe.attr_handle); } else if (event->subscribe.prev_notify == 1 && event->subscribe.cur_notify == 0) { - heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.UnsubscribeNotification(event->subscribe.attr_handle); + motionService.UnsubscribeNotification(event->subscribe.attr_handle); } break; diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 000231fe..8f1dfed7 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -58,12 +58,15 @@ namespace Pinetime { Pinetime::Controllers::MusicService& music() { return musicService; }; + Pinetime::Controllers::NavigationService& navigation() { return navService; }; + Pinetime::Controllers::AlertNotificationService& alertService() { return anService; }; + Pinetime::Controllers::WeatherService& weather() { return weatherService; }; diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h index 4c199dbf..09b5a561 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -51,9 +51,11 @@ namespace Pinetime { static constexpr size_t MaximumMessageSize() { return MessageSize; }; + bool IsEmpty() const { return size == 0; } + size_t NbNotifications() const; private: diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 23f53b74..e606d9bf 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -20,8 +20,8 @@ #include "libs/QCBOR/inc/qcbor/qcbor.h" #include "systemtask/SystemTask.h" -int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(connHandle, attrHandle, ctxt); +int WeatherCallback(uint16_t /*connHandle*/, uint16_t /*attrHandle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(ctxt); } namespace Pinetime { @@ -41,7 +41,7 @@ namespace Pinetime { ASSERT(res == 0); } - int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) { + int WeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) if (packetLen <= 0) { @@ -552,11 +552,12 @@ namespace Pinetime { int16_t WeatherService::GetTodayMinTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + uint64_t currentDayEnd = currentTimestamp + ((24 - dateTimeController.Hours()) * 60 * 60) + + ((60 - dateTimeController.Minutes()) * 60) + (60 - dateTimeController.Seconds()); + uint64_t currentDayStart = currentDayEnd - 86400; int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp >= currentDayStart && header->timestamp < currentDayEnd && reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature; @@ -575,11 +576,12 @@ namespace Pinetime { int16_t WeatherService::GetTodayMaxTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + uint64_t currentDayEnd = currentTimestamp + ((24 - dateTimeController.Hours()) * 60 * 60) + + ((60 - dateTimeController.Minutes()) * 60) + (60 - dateTimeController.Seconds()); + uint64_t currentDayStart = currentDayEnd - 86400; int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp >= currentDayStart && header->timestamp < currentDayEnd && reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature; diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index e37417da..00650e90 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -39,6 +39,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class WeatherService { @@ -47,7 +48,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); /* * Helper functions for quick access to currently valid data diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index 4dc16329..b744fbb2 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -20,14 +20,7 @@ void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, UpdateTime(previousSystickCounter); // Update internal state without updating the time } -void DateTime::SetTime(uint16_t year, - uint8_t month, - uint8_t day, - uint8_t dayOfWeek, - uint8_t hour, - uint8_t minute, - uint8_t second, - uint32_t systickCounter) { +void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) { std::tm tm = { /* .tm_sec = */ second, /* .tm_min = */ minute, @@ -36,6 +29,7 @@ void DateTime::SetTime(uint16_t year, /* .tm_mon = */ month - 1, /* .tm_year = */ year - 1900, }; + tm.tm_isdst = -1; // Use DST value from local time zone currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm)); @@ -50,6 +44,11 @@ void DateTime::SetTime(uint16_t year, systemTask->PushMessage(System::Messages::OnNewTime); } +void DateTime::SetTimeZone(int8_t timezone, int8_t dst) { + tzOffset = timezone; + dstOffset = dst; +} + void DateTime::UpdateTime(uint32_t systickCounter) { // Handle systick counter overflow uint32_t systickDelta = 0; @@ -136,6 +135,7 @@ void DateTime::Register(Pinetime::System::SystemTask* systemTask) { } using ClockType = Pinetime::Controllers::Settings::ClockType; + std::string DateTime::FormattedTime() { // Return time as a string in 12- or 24-hour format char buff[9]; diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 81319d15..74ccf4da 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -9,6 +9,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class DateTime { public: @@ -30,37 +31,85 @@ namespace Pinetime { December }; - void SetTime(uint16_t year, - uint8_t month, - uint8_t day, - uint8_t dayOfWeek, - uint8_t hour, - uint8_t minute, - uint8_t second, - uint32_t systickCounter); + void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter); + + /* + * setter corresponding to the BLE Set Local Time characteristic. + * + * used to update difference between utc and local time (see UtcOffset()) + * + * parameters are in quarters of an our. Following the BLE CTS specification, + * timezone is expected to be constant over DST which will be reported in + * dst field. + */ + void SetTimeZone(int8_t timezone, int8_t dst); + void UpdateTime(uint32_t systickCounter); + uint16_t Year() const { return year; } + Months Month() const { return month; } + uint8_t Day() const { return day; } + Days DayOfWeek() const { return dayOfWeek; } + uint8_t Hours() const { return hour; } + uint8_t Minutes() const { return minute; } + uint8_t Seconds() const { return second; } + /* + * returns the offset between local time and UTC in quarters of an hour + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t UtcOffset() const { + return tzOffset + dstOffset; + } + + /* + * returns the offset between the (dst independent) local time zone and UTC + * in quarters of an hour + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t TzOffset() const { + return tzOffset; + } + + /* + * returns the offset between the local time zone and local time + * in quarters of an hour + * if != 0, DST is in effect, if == 0 not. + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t DstOffset() const { + return dstOffset; + } + const char* MonthShortToString() const; const char* DayOfWeekShortToString() const; static const char* MonthShortToStringLow(Months month); @@ -69,6 +118,11 @@ namespace Pinetime { std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; } + + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const { + return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60); + } + std::chrono::seconds Uptime() const { return uptime; } @@ -85,6 +139,8 @@ namespace Pinetime { uint8_t hour = 0; uint8_t minute = 0; uint8_t second = 0; + int8_t tzOffset = 0; + int8_t dstOffset = 0; uint32_t previousSystickCounter = 0; std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime; diff --git a/src/components/fs/FS.cpp b/src/components/fs/FS.cpp index 14b05525..0bb59afa 100644 --- a/src/components/fs/FS.cpp +++ b/src/components/fs/FS.cpp @@ -89,18 +89,23 @@ int FS::DirClose(lfs_dir_t* lfs_dir) { int FS::DirRead(lfs_dir_t* dir, lfs_info* info) { return lfs_dir_read(&lfs, dir, info); } + int FS::DirRewind(lfs_dir_t* dir) { return lfs_dir_rewind(&lfs, dir); } + int FS::DirCreate(const char* path) { return lfs_mkdir(&lfs, path); } + int FS::Rename(const char* oldPath, const char* newPath) { return lfs_rename(&lfs, oldPath, newPath); } + int FS::Stat(const char* path, lfs_info* info) { return lfs_stat(&lfs, path, info); } + lfs_ssize_t FS::GetFSSize() { return lfs_fs_size(&lfs); } @@ -110,7 +115,7 @@ lfs_ssize_t FS::GetFSSize() { ----------- Interface between littlefs and SpiNorFlash ----------- */ -int FS::SectorSync(const struct lfs_config* c) { +int FS::SectorSync(const struct lfs_config* /*c*/) { return 0; } @@ -142,7 +147,7 @@ int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, */ namespace { - lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { + 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); int res = filesys->FileOpen(file, path, LFS_O_RDONLY); @@ -195,4 +200,4 @@ void FS::LVGLFileSystemInit() { fs_drv.user_data = this; lv_fs_drv_register(&fs_drv); -}
\ No newline at end of file +} diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h index 87fcdc23..9730e474 100644 --- a/src/components/fs/FS.h +++ b/src/components/fs/FS.h @@ -35,6 +35,7 @@ namespace Pinetime { static size_t getSize() { return size; } + static size_t getBlockSize() { return blockSize; } diff --git a/src/components/gfx/Gfx.h b/src/components/gfx/Gfx.h index 54c4a8b7..17c248f7 100644 --- a/src/components/gfx/Gfx.h +++ b/src/components/gfx/Gfx.h @@ -10,6 +10,7 @@ namespace Pinetime { namespace Drivers { class St7789; } + namespace Components { class Gfx : public Pinetime::Drivers::BufferProvider { public: @@ -33,9 +34,11 @@ namespace Pinetime { static constexpr uint8_t height = 240; enum class Action { None, FillRectangle, DrawChar }; + struct State { State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} { } + volatile bool busy; volatile Action action; volatile uint16_t remainingIterations; diff --git a/src/components/heartrate/HeartRateController.h b/src/components/heartrate/HeartRateController.h index a63f1a70..f66c79f8 100644 --- a/src/components/heartrate/HeartRateController.h +++ b/src/components/heartrate/HeartRateController.h @@ -7,9 +7,11 @@ namespace Pinetime { namespace Applications { class HeartRateTask; } + namespace System { class SystemTask; } + namespace Controllers { class HeartRateController { public: @@ -21,9 +23,11 @@ namespace Pinetime { void Update(States newState, uint8_t heartRate); void SetHeartRateTask(Applications::HeartRateTask* task); + States State() const { return state; } + uint8_t HeartRate() const { return heartRate; } diff --git a/src/components/heartrate/Ppg.cpp b/src/components/heartrate/Ppg.cpp index a5d83696..900b1c22 100644 --- a/src/components/heartrate/Ppg.cpp +++ b/src/components/heartrate/Ppg.cpp @@ -29,8 +29,9 @@ namespace { auto z1 = CompareShift(d, mn - 1, size); for (int i = mn; i < mx + 1; i++) { auto z = CompareShift(d, i, size); - if (z2 > z1 && z1 < z) + if (z2 > z1 && z1 < z) { return i; + } z2 = z1; z1 = z; } @@ -52,41 +53,48 @@ int8_t Ppg::Preprocess(float spl) { auto spl_int = static_cast<int8_t>(spl); - if (dataIndex < 200) + if (dataIndex < 200) { data[dataIndex++] = spl_int; + } return spl_int; } -float Ppg::HeartRate() { - if (dataIndex < 200) +int Ppg::HeartRate() { + if (dataIndex < 200) { return 0; + } NRF_LOG_INFO("PREPROCESS, offset = %d", offset); auto hr = ProcessHeartRate(); dataIndex = 0; return hr; } -float Ppg::ProcessHeartRate() { - auto t0 = Trough(data.data(), dataIndex, 7, 48); - if (t0 < 0) + +int Ppg::ProcessHeartRate() { + int t0 = Trough(data.data(), dataIndex, 7, 48); + if (t0 < 0) { return 0; + } - float t1 = t0 * 2; + int t1 = t0 * 2; t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5); - if (t1 < 0) + if (t1 < 0) { return 0; + } - float t2 = static_cast<int>(t1 * 3) / 2; + int t2 = (t1 * 3) / 2; t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5); - if (t2 < 0) + if (t2 < 0) { return 0; + } - float t3 = static_cast<int>(t2 * 4) / 3; + int t3 = (t2 * 4) / 3; t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4); - if (t3 < 0) - return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2); + if (t3 < 0) { + return (60 * 24 * 3) / t2; + } - return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3); + return (60 * 24 * 4) / t3; } void Ppg::SetOffset(uint16_t offset) { diff --git a/src/components/heartrate/Ppg.h b/src/components/heartrate/Ppg.h index 7000c871..1f709bab 100644 --- a/src/components/heartrate/Ppg.h +++ b/src/components/heartrate/Ppg.h @@ -12,9 +12,9 @@ namespace Pinetime { public: Ppg(); int8_t Preprocess(float spl); - float HeartRate(); + int HeartRate(); - void SetOffset(uint16_t i); + void SetOffset(uint16_t offset); void Reset(); private: @@ -25,7 +25,7 @@ namespace Pinetime { Ptagc agc; Biquad lpf; - float ProcessHeartRate(); + int ProcessHeartRate(); }; } } diff --git a/src/components/heartrate/Ptagc.cpp b/src/components/heartrate/Ptagc.cpp index 1c60bc23..221be460 100644 --- a/src/components/heartrate/Ptagc.cpp +++ b/src/components/heartrate/Ptagc.cpp @@ -14,13 +14,15 @@ Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {d } float Ptagc::Step(float spl) { - if (std::abs(spl) > peak) + if (std::abs(spl) > peak) { peak *= boost; - else + } else { peak *= decay; + } - if ((spl > (peak * threshold)) || (spl < (peak * -threshold))) + if ((spl > (peak * threshold)) || (spl < (peak * -threshold))) { return 0.0f; + } spl = 100.0f * spl / (2.0f * peak); return spl; diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp index 7dd32127..8ba46814 100644 --- a/src/components/motion/MotionController.cpp +++ b/src/components/motion/MotionController.cpp @@ -26,10 +26,9 @@ bool MotionController::Should_RaiseWake(bool isSleeping) { if (not isSleeping) { if (y <= 0) { return false; - } else { - lastYForWakeUp = 0; - return false; } + lastYForWakeUp = 0; + return false; } if (y >= 0) { @@ -62,6 +61,7 @@ bool MotionController::Should_ShakeWake(uint16_t thresh) { lastZForShake = z; return wake; } + int32_t MotionController::currentShakeSpeed() { return accumulatedspeed; } @@ -69,6 +69,7 @@ int32_t MotionController::currentShakeSpeed() { void MotionController::IsSensorOk(bool isOk) { isSensorOk = isOk; } + void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { switch (types) { case Drivers::Bma421::DeviceTypes::BMA421: @@ -82,6 +83,7 @@ void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { break; } } + void MotionController::SetService(Pinetime::Controllers::MotionService* service) { this->service = service; } diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index f80b11b9..857bd45a 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -19,12 +19,15 @@ namespace Pinetime { int16_t X() const { return x; } + int16_t Y() const { return y; } + int16_t Z() const { return z; } + uint32_t NbSteps() const { return nbSteps; } @@ -32,6 +35,7 @@ namespace Pinetime { void ResetTrip() { currentTripSteps = 0; } + uint32_t GetTripSteps() const { return currentTripSteps; } @@ -40,6 +44,7 @@ namespace Pinetime { bool Should_RaiseWake(bool isSleeping); int32_t currentShakeSpeed(); void IsSensorOk(bool isOk); + bool IsSensorOk() const { return isSensorOk; } diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index db6103f4..4e392416 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -34,6 +34,6 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } -void MotorController::StopMotor(TimerHandle_t xTimer) { +void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_gpio_pin_set(PinMap::Motor); } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 93f861f3..d1e71656 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -45,6 +45,7 @@ namespace Pinetime { Colors ColorBG = Colors::Black; PTSGaugeStyle gaugeStyle = PTSGaugeStyle::Full; }; + struct WatchFaceInfineat { bool showSideCover = true; int colorIndex = 0; @@ -66,6 +67,7 @@ namespace Pinetime { } settings.clockFace = face; }; + uint8_t GetClockFace() const { return settings.clockFace; }; @@ -76,6 +78,7 @@ namespace Pinetime { } settings.chimesOption = chimeOption; }; + ChimesOption GetChimeOption() const { return settings.chimesOption; }; @@ -85,6 +88,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorTime = colorTime; }; + Colors GetPTSColorTime() const { return settings.PTS.ColorTime; }; @@ -94,6 +98,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorBar = colorBar; }; + Colors GetPTSColorBar() const { return settings.PTS.ColorBar; }; @@ -103,6 +108,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorBG = colorBG; }; + Colors GetPTSColorBG() const { return settings.PTS.ColorBG; }; @@ -113,6 +119,7 @@ namespace Pinetime { settingsChanged = true; } }; + bool GetInfineatShowSideCover() const { return settings.watchFaceInfineat.showSideCover; }; @@ -123,6 +130,7 @@ namespace Pinetime { settingsChanged = true; } }; + int GetInfineatColorIndex() const { return settings.watchFaceInfineat.colorIndex; }; @@ -132,6 +140,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.gaugeStyle = gaugeStyle; }; + PTSGaugeStyle GetPTSGaugeStyle() const { return settings.PTS.gaugeStyle; }; @@ -147,6 +156,7 @@ namespace Pinetime { void SetSettingsMenu(uint8_t menu) { settingsMenu = menu; }; + uint8_t GetSettingsMenu() const { return settingsMenu; }; @@ -157,6 +167,7 @@ namespace Pinetime { } settings.clockType = clocktype; }; + ClockType GetClockType() const { return settings.clockType; }; @@ -167,6 +178,7 @@ namespace Pinetime { } settings.notificationStatus = status; }; + Notification GetNotificationStatus() const { return settings.notificationStatus; }; @@ -255,6 +267,7 @@ namespace Pinetime { Pinetime::Controllers::FS& fs; static constexpr uint32_t settingsVersion = 0x0004; + struct SettingsData { uint32_t version = settingsVersion; uint32_t stepsGoal = 10000; diff --git a/src/components/timer/TimerController.h b/src/components/timer/TimerController.h index 93d8afc6..20f07e82 100644 --- a/src/components/timer/TimerController.h +++ b/src/components/timer/TimerController.h @@ -7,6 +7,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class TimerController { diff --git a/src/components/utility/LinearApproximation.h b/src/components/utility/LinearApproximation.h new file mode 100644 index 00000000..f7104ced --- /dev/null +++ b/src/components/utility/LinearApproximation.h @@ -0,0 +1,41 @@ +#pragma once + +#include <cstddef> +#include <array> + +namespace Pinetime { + namespace Utility { + + // based on: https://github.com/SHristov92/LinearApproximation/blob/main/Linear.h + template <typename Key, typename Value, std::size_t Size> class LinearApproximation { + using Point = struct { + Key key; + Value value; + }; + + public: + LinearApproximation(const std::array<Point, Size>&& sorted_points) : points {sorted_points} { + } + + Value GetValue(Key key) const { + if (key <= points[0].key) { + return points[0].value; + } + + for (std::size_t i = 1; i < Size; i++) { + const auto& p = points[i]; + const auto& p_prev = points[i - 1]; + + if (key < p.key) { + return p_prev.value + (key - p_prev.key) * (p.value - p_prev.value) / (p.key - p_prev.key); + } + } + + return points[Size - 1].value; + } + + private: + std::array<Point, Size> points; + }; + } +} diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index 8aad9535..89b05d87 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -34,8 +34,7 @@ namespace Pinetime { SettingDisplay, SettingWakeUp, SettingSteps, - SettingSetDate, - SettingSetTime, + SettingSetDateTime, SettingChimes, SettingShakeThreshold, SettingBluetooth, diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 108e380d..725caaf4 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -43,8 +43,7 @@ #include "displayapp/screens/settings/SettingWakeUp.h" #include "displayapp/screens/settings/SettingDisplay.h" #include "displayapp/screens/settings/SettingSteps.h" -#include "displayapp/screens/settings/SettingSetDate.h" -#include "displayapp/screens/settings/SettingSetTime.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" @@ -102,9 +101,9 @@ void DisplayApp::Start(System::BootErrors error) { bootError = error; if (error == System::BootErrors::TouchController) { - LoadApp(Apps::Error, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None); } else { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); } if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) { @@ -132,7 +131,25 @@ void DisplayApp::InitHw() { void DisplayApp::Refresh() { auto LoadPreviousScreen = [this]() { - LoadApp(returnToApp, returnDirection); + FullRefreshDirections returnDirection; + switch (appStackDirections.Pop()) { + case FullRefreshDirections::Up: + returnDirection = FullRefreshDirections::Down; + break; + case FullRefreshDirections::Down: + returnDirection = FullRefreshDirections::Up; + break; + case FullRefreshDirections::LeftAnim: + returnDirection = FullRefreshDirections::RightAnim; + break; + case FullRefreshDirections::RightAnim: + returnDirection = FullRefreshDirections::LeftAnim; + break; + default: + returnDirection = FullRefreshDirections::None; + break; + } + LoadScreen(returnAppStack.Pop(), returnDirection); }; TickType_t queueTimeout; @@ -152,7 +169,7 @@ void DisplayApp::Refresh() { } Messages msg; - if (xQueueReceive(msgQueue, &msg, queueTimeout)) { + if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) { switch (msg) { case Messages::DimScreen: brightnessController.Set(Controllers::BrightnessController::Levels::Low); @@ -180,14 +197,14 @@ void DisplayApp::Refresh() { // Screens::Clock::BleConnectionStates::NotConnected); break; case Messages::NewNotification: - LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); break; case Messages::TimerDone: if (currentApp == Apps::Timer) { auto* timer = static_cast<Screens::Timer*>(currentScreen.get()); timer->Reset(); } else { - LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); } break; case Messages::AlarmTriggered: @@ -195,11 +212,11 @@ void DisplayApp::Refresh() { auto* alarm = static_cast<Screens::Alarm*>(currentScreen.get()); alarm->SetAlerting(); } else { - LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Alarm, DisplayApp::FullRefreshDirections::None); } break; case Messages::ShowPairingKey: - LoadApp(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); break; case Messages::TouchEvent: { if (state != States::Running) { @@ -209,17 +226,30 @@ void DisplayApp::Refresh() { if (gesture == TouchEvents::None) { break; } + auto LoadDirToReturnSwipe = [](DisplayApp::FullRefreshDirections refreshDirection) { + switch (refreshDirection) { + default: + case DisplayApp::FullRefreshDirections::Up: + return TouchEvents::SwipeDown; + case DisplayApp::FullRefreshDirections::Down: + return TouchEvents::SwipeUp; + case DisplayApp::FullRefreshDirections::LeftAnim: + return TouchEvents::SwipeRight; + case DisplayApp::FullRefreshDirections::RightAnim: + return TouchEvents::SwipeLeft; + } + }; if (!currentScreen->OnTouchEvent(gesture)) { if (currentApp == Apps::Clock) { switch (gesture) { case TouchEvents::SwipeUp: - LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::Launcher, DisplayApp::FullRefreshDirections::Up); break; case TouchEvents::SwipeDown: - LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); break; case TouchEvents::SwipeRight: - LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); + LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); break; case TouchEvents::DoubleTap: PushMessageToSystemTask(System::Messages::GoToSleep); @@ -227,7 +257,7 @@ void DisplayApp::Refresh() { default: break; } - } else if (returnTouchEvent == gesture) { + } else if (gesture == LoadDirToReturnSwipe(appStackDirections.Top())) { LoadPreviousScreen(); } } else { @@ -246,26 +276,28 @@ void DisplayApp::Refresh() { case Messages::ButtonLongPressed: if (currentApp != Apps::Clock) { if (currentApp == Apps::Notifications) { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::Up); } else if (currentApp == Apps::QuickSettings) { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); } else { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::Down); } + appStackDirections.Reset(); + returnAppStack.Reset(); } break; case Messages::ButtonLongerPressed: // Create reboot app and open it instead - LoadApp(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); break; case Messages::ButtonDoubleClicked: if (currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) { - LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); } break; case Messages::BleFirmwareUpdateStarted: - LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); break; case Messages::BleRadioEnableToggle: PushMessageToSystemTask(System::Messages::BleRadioEnableToggle); @@ -275,7 +307,7 @@ void DisplayApp::Refresh() { // What should happen here? break; case Messages::Clock: - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); break; } } @@ -285,7 +317,7 @@ void DisplayApp::Refresh() { } if (nextApp != Apps::None) { - LoadApp(nextApp, nextDirection); + LoadNewScreen(nextApp, nextDirection); nextApp = Apps::None; } } @@ -295,27 +327,28 @@ void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) nextDirection = direction; } -void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) { - returnToApp = app; - returnDirection = direction; - returnTouchEvent = touchEvent; +void DisplayApp::LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction) { + // Don't add the same screen to the stack back to back. + // This is mainly to fix an issue with receiving two notifications at the same time + // and shouldn't happen otherwise. + if (app != currentApp) { + returnAppStack.Push(currentApp); + appStackDirections.Push(direction); + } + LoadScreen(app, direction); } -void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) { +void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction) { touchHandler.CancelTap(); ApplyBrightness(); currentScreen.reset(nullptr); SetFullRefresh(direction); - // default return to launcher - ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown); - switch (app) { case Apps::Launcher: currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, bleController, dateTimeController); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::None: case Apps::Clock: @@ -332,21 +365,17 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Error: currentScreen = std::make_unique<Screens::Error>(this, bootError); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::FirmwareValidation: currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FirmwareUpdate: currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::PassKey: currentScreen = std::make_unique<Screens::PassKey>(this, bleController.GetPairingKey()); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::Notifications: @@ -356,7 +385,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, *systemTask, Screens::Notifications::Modes::Normal); - ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::NotificationsPreview: currentScreen = std::make_unique<Screens::Notifications>(this, @@ -365,7 +393,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, *systemTask, Screens::Notifications::Modes::Preview); - ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::Timer: currentScreen = std::make_unique<Screens::Timer>(this, timerController); @@ -383,55 +410,39 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, settingsController, bleController); - ReturnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft); break; case Apps::Settings: currentScreen = std::make_unique<Screens::Settings>(this, settingsController); - ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingWatchFace: currentScreen = std::make_unique<Screens::SettingWatchFace>(this, settingsController, filesystem); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingTimeFormat: currentScreen = std::make_unique<Screens::SettingTimeFormat>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingWakeUp: currentScreen = std::make_unique<Screens::SettingWakeUp>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingDisplay: currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingSteps: currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; - case Apps::SettingSetDate: - currentScreen = std::make_unique<Screens::SettingSetDate>(this, dateTimeController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); - break; - case Apps::SettingSetTime: - currentScreen = std::make_unique<Screens::SettingSetTime>(this, dateTimeController, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); + case Apps::SettingSetDateTime: + currentScreen = std::make_unique<Screens::SettingSetDateTime>(this, dateTimeController, settingsController); break; case Apps::SettingChimes: currentScreen = std::make_unique<Screens::SettingChimes>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingShakeThreshold: currentScreen = std::make_unique<Screens::SettingShakeThreshold>(this, settingsController, motionController, *systemTask); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingBluetooth: currentScreen = std::make_unique<Screens::SettingBluetooth>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::BatteryInfo: currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SysInfo: currentScreen = std::make_unique<Screens::SystemInfo>(this, @@ -442,11 +453,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) watchdog, motionController, touchPanel); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FlashLight: currentScreen = std::make_unique<Screens::FlashLight>(this, *systemTask, brightnessController); - ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::StopWatch: currentScreen = std::make_unique<Screens::StopWatch>(this, *systemTask); @@ -471,7 +480,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) break; case Apps::Metronome: currentScreen = std::make_unique<Screens::Metronome>(this, motorController, *systemTask); - ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::Motion: currentScreen = std::make_unique<Screens::Motion>(this, motionController); @@ -485,10 +493,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) void DisplayApp::PushMessage(Messages msg) { if (in_isr()) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { + if (xHigherPriorityTaskWoken == pdTRUE) { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } else { @@ -530,10 +537,10 @@ void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) { void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) { this->systemTask = systemTask; } + void DisplayApp::ApplyBrightness() { auto brightness = settingsController.GetBrightness(); - if(brightness != Controllers::BrightnessController::Levels::Low && - brightness != Controllers::BrightnessController::Levels::Medium && + if (brightness != Controllers::BrightnessController::Levels::Low && brightness != Controllers::BrightnessController::Levels::Medium && brightness != Controllers::BrightnessController::Levels::High) { brightness = Controllers::BrightnessController::Levels::High; } diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 4c54e227..c1d04cc9 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -20,6 +20,8 @@ #include "displayapp/Messages.h" #include "BootErrors.h" +#include "StaticStack.h" + namespace Pinetime { namespace Drivers { @@ -27,6 +29,7 @@ namespace Pinetime { class Cst816S; class WatchdogView; } + namespace Controllers { class Settings; class Battery; @@ -41,6 +44,7 @@ namespace Pinetime { namespace System { class SystemTask; }; + namespace Applications { class DisplayApp { public: @@ -114,14 +118,18 @@ namespace Pinetime { static void Process(void* instance); void InitHw(); void Refresh(); - void ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent); - void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction); + void LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction); + void LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction); void PushMessageToSystemTask(Pinetime::System::Messages message); Apps nextApp = Apps::None; DisplayApp::FullRefreshDirections nextDirection; System::BootErrors bootError; void ApplyBrightness(); + + static constexpr size_t returnAppStackSize = 10; + StaticStack<Apps, returnAppStackSize> returnAppStack; + StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections; }; } } diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index e553aa87..ecc01e9b 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -11,22 +11,22 @@ using namespace Pinetime::Applications; DisplayApp::DisplayApp(Drivers::St7789& lcd, - Components::LittleVgl& lvgl, - Drivers::Cst816S& touchPanel, - Controllers::Battery& batteryController, + Components::LittleVgl& /*lvgl*/, + Drivers::Cst816S& /*touchPanel*/, + Controllers::Battery& /*batteryController*/, Controllers::Ble& bleController, - Controllers::DateTime& dateTimeController, - Drivers::WatchdogView& watchdog, - Pinetime::Controllers::NotificationManager& notificationManager, - Pinetime::Controllers::HeartRateController& heartRateController, - Controllers::Settings& settingsController, - Pinetime::Controllers::MotorController& motorController, - Pinetime::Controllers::MotionController& motionController, - Pinetime::Controllers::TimerController& timerController, - Pinetime::Controllers::AlarmController& alarmController, - Pinetime::Controllers::BrightnessController& brightnessController, - Pinetime::Controllers::TouchHandler& touchHandler, - Pinetime::Controllers::FS& filesystem) + Controllers::DateTime& /*dateTimeController*/, + Drivers::WatchdogView& /*watchdog*/, + Pinetime::Controllers::NotificationManager& /*notificationManager*/, + Pinetime::Controllers::HeartRateController& /*heartRateController*/, + Controllers::Settings& /*settingsController*/, + Pinetime::Controllers::MotorController& /*motorController*/, + Pinetime::Controllers::MotionController& /*motionController*/, + Pinetime::Controllers::TimerController& /*timerController*/, + Pinetime::Controllers::AlarmController& /*alarmController*/, + Pinetime::Controllers::BrightnessController& /*brightnessController*/, + Pinetime::Controllers::TouchHandler& /*touchHandler*/, + Pinetime::Controllers::FS& /*filesystem*/) : lcd {lcd}, bleController {bleController} { } @@ -121,5 +121,5 @@ void DisplayApp::PushMessage(Display::Messages msg) { } } -void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) { +void DisplayApp::Register(Pinetime::System::SystemTask* /*systemTask*/) { } diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 7d4f0fd0..97aaca88 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -22,6 +22,7 @@ namespace Pinetime { class Cst816S; class WatchdogView; } + namespace Controllers { class Settings; class Battery; @@ -63,9 +64,11 @@ namespace Pinetime { Pinetime::Controllers::TouchHandler& touchHandler, Pinetime::Controllers::FS& filesystem); void Start(); + void Start(Pinetime::System::BootErrors) { Start(); }; + void PushMessage(Pinetime::Applications::Display::Messages msg); void Register(Pinetime::System::SystemTask* systemTask); diff --git a/src/displayapp/DummyLittleVgl.h b/src/displayapp/DummyLittleVgl.h index 05355a97..7a8ae999 100644 --- a/src/displayapp/DummyLittleVgl.h +++ b/src/displayapp/DummyLittleVgl.h @@ -11,6 +11,7 @@ namespace Pinetime { class LittleVgl { public: enum class FullRefreshDirections { None, Up, Down }; + LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) { } @@ -24,13 +25,17 @@ namespace Pinetime { void FlushDisplay(const lv_area_t* area, lv_color_t* color_p) { } + bool GetTouchPadInfo(lv_indev_data_t* ptr) { return false; } + void SetFullRefresh(FullRefreshDirections direction) { } + void SetNewTapEvent(uint16_t x, uint16_t y) { } + void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) { } }; diff --git a/src/displayapp/InfiniTimeTheme.cpp b/src/displayapp/InfiniTimeTheme.cpp index 4290d87f..6795647e 100644 --- a/src/displayapp/InfiniTimeTheme.cpp +++ b/src/displayapp/InfiniTimeTheme.cpp @@ -1,4 +1,17 @@ #include "displayapp/InfiniTimeTheme.h" +#include <algorithm> + +// Replace LV_DPX with a constexpr version using a constant LV_DPI +#undef LV_DPX + +namespace { + constexpr int LV_DPX(int n) { + if (n == 0) { + return 0; + } + return std::max(((LV_DPI * n + 80) / 160), 1); /*+80 for rounding*/ + } +} static void theme_apply(lv_obj_t* obj, lv_theme_style_t name); @@ -47,7 +60,6 @@ static void basic_init() { style_init_reset(&style_box); lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10); - lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, Colors::bg); lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal); style_init_reset(&style_label_white); @@ -60,25 +72,12 @@ static void basic_init() { lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, Colors::bg); lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, Colors::highlight); lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, Colors::bgDark); - lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0); lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); - lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); - - lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_all(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15)); - lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0); - lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0); - lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0); style_init_reset(&style_icon); lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_COLOR_WHITE); @@ -132,10 +131,7 @@ static void basic_init() { lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_COLOR_SILVER); lv_style_set_bg_color(&style_sw_knob, LV_STATE_CHECKED, LV_COLOR_WHITE); lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, -4); + lv_style_set_pad_all(&style_sw_knob, LV_STATE_DEFAULT, -4); style_init_reset(&style_slider_knob); lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); @@ -143,14 +139,8 @@ static void basic_init() { lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6); lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14); + lv_style_set_pad_all(&style_slider_knob, LV_STATE_DEFAULT, 10); + lv_style_set_pad_all(&style_slider_knob, LV_STATE_PRESSED, 14); style_init_reset(&style_arc_indic); lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, Colors::lightGray); @@ -180,10 +170,7 @@ static void basic_init() { style_init_reset(&style_pad_small); lv_style_int_t pad_small_value = 10; - lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_all(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); style_init_reset(&style_lmeter); @@ -209,20 +196,12 @@ static void basic_init() { lv_style_reset(&style_cb_bg); lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, 18); - lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0); - lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); lv_style_reset(&style_cb_bullet); lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4)); lv_style_set_pattern_image(&style_cb_bullet, LV_STATE_CHECKED, LV_SYMBOL_OK); lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_pad_all(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); } /** @@ -236,20 +215,14 @@ static void basic_init() { * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, - lv_color_t color_secondary, - uint32_t flags, - const lv_font_t* font_small, - const lv_font_t* font_normal, - const lv_font_t* font_subtitle, - const lv_font_t* font_title) { - theme.color_primary = color_primary; - theme.color_secondary = color_secondary; - theme.font_small = font_small; - theme.font_normal = font_normal; - theme.font_subtitle = font_subtitle; - theme.font_title = font_title; - theme.flags = flags; +lv_theme_t* lv_pinetime_theme_init() { + theme.color_primary = LV_COLOR_WHITE; + theme.color_secondary = LV_COLOR_GRAY; + theme.font_small = &jetbrains_mono_bold_20; + theme.font_normal = &jetbrains_mono_bold_20; + theme.font_subtitle = &jetbrains_mono_bold_20; + theme.font_title = &jetbrains_mono_bold_20; + theme.flags = 0; basic_init(); diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 5709b007..52c339dd 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -24,10 +24,4 @@ namespace Colors { * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, - lv_color_t color_secondary, - uint32_t flags, - const lv_font_t* font_small, - const lv_font_t* font_normal, - const lv_font_t* font_subtitle, - const lv_font_t* font_title); +lv_theme_t* lv_pinetime_theme_init(); diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index d5f31848..e3d564a3 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -3,13 +3,17 @@ #include <FreeRTOS.h> #include <task.h> -//#include <projdefs.h> #include "drivers/Cst816s.h" #include "drivers/St7789.h" using namespace Pinetime::Components; -lv_style_t* LabelBigStyle = nullptr; +namespace { + void InitTheme() { + lv_theme_t* theme = lv_pinetime_theme_init(); + lv_theme_set_act(theme); + } +} static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) { auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data); @@ -192,16 +196,3 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) { } return false; } - -void LittleVgl::InitTheme() { - - lv_theme_t* th = lv_pinetime_theme_init(LV_COLOR_WHITE, - LV_COLOR_SILVER, - 0, - &jetbrains_mono_bold_20, - &jetbrains_mono_bold_20, - &jetbrains_mono_bold_20, - &jetbrains_mono_bold_20); - - lv_theme_set_act(th); -} diff --git a/src/displayapp/LittleVgl.h b/src/displayapp/LittleVgl.h index 45826165..7bd0198c 100644 --- a/src/displayapp/LittleVgl.h +++ b/src/displayapp/LittleVgl.h @@ -37,7 +37,6 @@ namespace Pinetime { private: void InitDisplay(); void InitTouchpad(); - void InitTheme(); Pinetime::Drivers::St7789& lcd; Pinetime::Drivers::Cst816S& touchPanel; @@ -52,9 +51,11 @@ namespace Pinetime { static constexpr uint8_t nbWriteLines = 4; static constexpr uint16_t totalNbLines = 320; static constexpr uint16_t visibleNbLines = 240; + static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; } + FullRefreshDirections scrollDirection = FullRefreshDirections::None; uint16_t writeOffset = 0; uint16_t scrollOffset = 0; diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index 58df4556..afa7709a 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -1,5 +1,6 @@ #pragma once #include <cstdint> + namespace Pinetime { namespace Applications { namespace Display { diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 9febda61..87d1f2e1 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -59,7 +59,7 @@ void BatteryInfo::Refresh() { } 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) { + } else if (batteryController.BatteryIsLow()) { 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 { diff --git a/src/displayapp/screens/CheckboxList.cpp b/src/displayapp/screens/CheckboxList.cpp index c189b075..928b2e61 100644 --- a/src/displayapp/screens/CheckboxList.cpp +++ b/src/displayapp/screens/CheckboxList.cpp @@ -28,7 +28,9 @@ CheckboxList::CheckboxList(const uint8_t screenID, // Set the background to Black lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - pageIndicator.Create(); + if (numScreens > 1) { + pageIndicator.Create(); + } lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); diff --git a/src/displayapp/screens/CheckboxList.h b/src/displayapp/screens/CheckboxList.h index 48125d4b..359b835e 100644 --- a/src/displayapp/screens/CheckboxList.h +++ b/src/displayapp/screens/CheckboxList.h @@ -15,6 +15,7 @@ namespace Pinetime { class CheckboxList : public Screen { public: static constexpr size_t MaxItems = 4; + struct Item { const char* name; bool enabled; diff --git a/src/displayapp/screens/FirmwareUpdate.h b/src/displayapp/screens/FirmwareUpdate.h index 5156b7ea..cc3b09b2 100644 --- a/src/displayapp/screens/FirmwareUpdate.h +++ b/src/displayapp/screens/FirmwareUpdate.h @@ -8,6 +8,7 @@ namespace Pinetime { namespace Controllers { class Ble; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp index a2314690..bda6d68d 100644 --- a/src/displayapp/screens/FirmwareValidation.cpp +++ b/src/displayapp/screens/FirmwareValidation.cpp @@ -32,16 +32,16 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK); lv_obj_set_width(labelIsValidated, 240); - if (validator.IsValidated()) + if (validator.IsValidated()) { lv_label_set_text_static(labelIsValidated, "You have already\n#00ff00 validated# this firmware#"); - else { + } else { lv_label_set_text_static(labelIsValidated, "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version."); buttonValidate = lv_btn_create(lv_scr_act(), nullptr); buttonValidate->user_data = this; lv_obj_set_size(buttonValidate, 115, 50); - lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_align(buttonValidate, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_set_event_cb(buttonValidate, ButtonEventHandler); lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp index 305e0c4b..71bf86ca 100644 --- a/src/displayapp/screens/HeartRate.cpp +++ b/src/displayapp/screens/HeartRate.cpp @@ -64,8 +64,9 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app, label_startStop = lv_label_create(btn_startStop, nullptr); UpdateStartStopButton(isHrRunning); - if (isHrRunning) + if (isHrRunning) { systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); + } taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); } @@ -110,8 +111,9 @@ void HeartRate::OnStartStopEvent(lv_event_t event) { } void HeartRate::UpdateStartStopButton(bool isRunning) { - if (isRunning) + if (isRunning) { lv_label_set_text_static(label_startStop, "Stop"); - else + } else { lv_label_set_text_static(label_startStop, "Start"); + } } diff --git a/src/displayapp/screens/HeartRate.h b/src/displayapp/screens/HeartRate.h index 2ad00351..d68133ad 100644 --- a/src/displayapp/screens/HeartRate.h +++ b/src/displayapp/screens/HeartRate.h @@ -11,6 +11,7 @@ namespace Pinetime { namespace Controllers { class HeartRateController; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/InfiniPaint.h b/src/displayapp/screens/InfiniPaint.h index 8c427402..a6b6eb18 100644 --- a/src/displayapp/screens/InfiniPaint.h +++ b/src/displayapp/screens/InfiniPaint.h @@ -10,6 +10,7 @@ namespace Pinetime { namespace Components { class LittleVgl; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/List.cpp b/src/displayapp/screens/List.cpp index f44825c7..3f219ea1 100644 --- a/src/displayapp/screens/List.cpp +++ b/src/displayapp/screens/List.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/List.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -25,41 +26,44 @@ List::List(uint8_t screenID, pageIndicator.Create(); - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); + lv_obj_t* container = lv_cont_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 4); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + static constexpr int innerPad = 4; + lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, innerPad); + lv_obj_set_style_local_border_width(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); - lv_obj_set_pos(container1, 0, 0); - lv_obj_set_width(container1, LV_HOR_RES - 8); - lv_obj_set_height(container1, LV_VER_RES); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* labelBt; - lv_obj_t* labelBtIco; + lv_obj_set_pos(container, 0, 0); + lv_obj_set_width(container, LV_HOR_RES - 8); + lv_obj_set_height(container, LV_VER_RES); + lv_cont_set_layout(container, LV_LAYOUT_COLUMN_LEFT); for (int i = 0; i < MAXLISTITEMS; i++) { apps[i] = applications[i].application; if (applications[i].application != Apps::None) { - itemApps[i] = lv_btn_create(container1, nullptr); - lv_obj_set_style_local_bg_opa(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50); - lv_obj_set_style_local_radius(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 57); - lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - + static constexpr int btnHeight = (LV_HOR_RES_MAX - ((MAXLISTITEMS - 1) * innerPad)) / MAXLISTITEMS; + itemApps[i] = lv_btn_create(container, nullptr); + lv_obj_set_style_local_radius(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, btnHeight / 3); + lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_width(itemApps[i], LV_HOR_RES - 8); - lv_obj_set_height(itemApps[i], 57); + lv_obj_set_height(itemApps[i], btnHeight); lv_obj_set_event_cb(itemApps[i], ButtonEventHandler); - lv_btn_set_layout(itemApps[i], LV_LAYOUT_ROW_MID); + lv_btn_set_layout(itemApps[i], LV_LAYOUT_OFF); itemApps[i]->user_data = this; + lv_obj_set_style_local_clip_corner(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, true); - labelBtIco = lv_label_create(itemApps[i], nullptr); - lv_obj_set_style_local_text_color(labelBtIco, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); - lv_label_set_text_static(labelBtIco, applications[i].icon); + lv_obj_t* icon = lv_label_create(itemApps[i], nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + lv_label_set_text_static(icon, applications[i].icon); + lv_label_set_long_mode(icon, LV_LABEL_LONG_CROP); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_set_width(icon, btnHeight); + lv_obj_align(icon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, 0); - labelBt = lv_label_create(itemApps[i], nullptr); - lv_label_set_text_fmt(labelBt, " %s", applications[i].name); + lv_obj_t* text = lv_label_create(itemApps[i], nullptr); + lv_label_set_text_fmt(text, "%s", applications[i].name); + lv_obj_align(text, icon, LV_ALIGN_OUT_RIGHT_MID, 0, 0); } } } diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp index df87092b..40456ab8 100644 --- a/src/displayapp/screens/Metronome.cpp +++ b/src/displayapp/screens/Metronome.cpp @@ -146,7 +146,6 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) { bool Metronome::OnTouchEvent(TouchEvents event) { if (event == TouchEvents::SwipeDown && allowExit) { running = false; - return true; } - return false; + return true; } diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp index c2dc4dac..e3689599 100644 --- a/src/displayapp/screens/Motion.cpp +++ b/src/displayapp/screens/Motion.cpp @@ -7,9 +7,9 @@ using namespace Pinetime::Applications::Screens; Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionController& motionController) : Screen(app), motionController {motionController} { - chart = lv_chart_create(lv_scr_act(), NULL); + chart = lv_chart_create(lv_scr_act(), nullptr); lv_obj_set_size(chart, 240, 240); - lv_obj_align(chart, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_align(chart, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/ // lv_chart_set_series_opa(chart, LV_OPA_70); /*Opacity of the data series*/ // lv_chart_set_series_width(chart, 4); /*Line width and point radious*/ @@ -28,13 +28,13 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr lv_chart_init_points(chart, ser3, 0); lv_chart_refresh(chart); /*Required after direct set*/ - label = lv_label_create(lv_scr_act(), NULL); + label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_fmt(label, "X #FF0000 %d# Y #00B000 %d# Z #FFFF00 %d#", 0, 0, 0); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); - lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10); + lv_obj_align(label, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10); lv_label_set_recolor(label, true); - labelStep = lv_label_create(lv_scr_act(), NULL); + labelStep = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_label_set_text_static(labelStep, "Steps ---"); @@ -58,5 +58,5 @@ void Motion::Refresh() { motionController.X() / 0x10, motionController.Y() / 0x10, motionController.Z() / 0x10); - lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10); + lv_obj_align(label, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10); } diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 90a010f5..6c68c70d 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -79,9 +79,12 @@ void Notifications::Refresh() { timeoutLinePoints[1].x = pos; lv_line_set_points(timeoutLine, timeoutLinePoints, 2); } - } - if (dismissingNotification) { + } else if (mode == Modes::Preview && dismissingNotification) { + running = false; + currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController); + + } else if (dismissingNotification) { dismissingNotification = false; auto notification = notificationManager.Get(currentId); if (!notification.valid) { @@ -126,12 +129,34 @@ void Notifications::OnPreviewInteraction() { } } +void Notifications::DismissToBlack() { + currentItem.reset(nullptr); + app->SetFullRefresh(DisplayApp::FullRefreshDirections::RightAnim); + // create black transition screen to let the notification dismiss to blackness + lv_obj_t* blackBox = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(blackBox, LV_HOR_RES, LV_VER_RES); + lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + dismissingNotification = true; +} + +void Notifications::OnPreviewDismiss() { + notificationManager.Dismiss(currentId); + if (timeoutLine != nullptr) { + lv_obj_del(timeoutLine); + timeoutLine = nullptr; + } + DismissToBlack(); +} + bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { if (mode != Modes::Normal) { if (!interacted && event == TouchEvents::Tap) { interacted = true; OnPreviewInteraction(); return true; + } else if (event == Pinetime::Applications::TouchEvents::SwipeRight) { + OnPreviewDismiss(); + return true; } return false; } @@ -139,15 +164,9 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { case Pinetime::Applications::TouchEvents::SwipeRight: if (validDisplay) { - Controllers::NotificationManager::Notification previousNotification; auto previousMessage = notificationManager.GetPrevious(currentId); auto nextMessage = notificationManager.GetNext(currentId); - if (!previousMessage.valid) { - // dismissed last message (like 5/5), need to go one message down (like 4/4) - afterDismissNextMessageFromAbove = false; // show next message coming from below - } else { - afterDismissNextMessageFromAbove = true; // show next message coming from above - } + afterDismissNextMessageFromAbove = previousMessage.valid; notificationManager.Dismiss(currentId); if (previousMessage.valid) { currentId = previousMessage.id; @@ -156,13 +175,7 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } else { // don't update id, won't be found be refresh and try to load latest message or no message box } - currentItem.reset(nullptr); - app->SetFullRefresh(DisplayApp::FullRefreshDirections::RightAnim); - // create black transition screen to let the notification dismiss to blackness - lv_obj_t* blackBox = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_size(blackBox, LV_HOR_RES, LV_VER_RES); - lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - dismissingNotification = true; + DismissToBlack(); return true; } return false; @@ -270,7 +283,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, lv_obj_t* alert_count = lv_label_create(container, nullptr); lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb); - lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16); + lv_obj_align(alert_count, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 16); lv_obj_t* alert_type = lv_label_create(container, nullptr); lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); @@ -288,7 +301,7 @@ Notifications::NotificationItem::NotificationItem(const char* 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); + lv_obj_align(alert_type, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 16); lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr); lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK); @@ -312,7 +325,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, bt_accept->user_data = this; lv_obj_set_event_cb(bt_accept, CallEventHandler); lv_obj_set_size(bt_accept, 76, 76); - lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_align(bt_accept, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); label_accept = lv_label_create(bt_accept, nullptr); lv_label_set_text_static(label_accept, Symbols::phone); lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); @@ -321,7 +334,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, bt_reject->user_data = this; lv_obj_set_event_cb(bt_reject, CallEventHandler); lv_obj_set_size(bt_reject, 76, 76); - lv_obj_align(bt_reject, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_align(bt_reject, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); label_reject = lv_label_create(bt_reject, nullptr); lv_label_set_text_static(label_reject, Symbols::phoneSlash); lv_obj_set_style_local_bg_color(bt_reject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); @@ -330,7 +343,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, bt_mute->user_data = this; lv_obj_set_event_cb(bt_mute, CallEventHandler); lv_obj_set_size(bt_mute, 76, 76); - lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_align(bt_mute, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); label_mute = lv_label_create(bt_mute, nullptr); lv_label_set_text_static(label_mute, Symbols::volumMute); lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index 9d843a9b..a4d2709b 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -13,6 +13,7 @@ namespace Pinetime { namespace Controllers { class AlertNotificationService; } + namespace Applications { namespace Screens { @@ -29,7 +30,9 @@ namespace Pinetime { void Refresh() override; bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; + void DismissToBlack(); void OnPreviewInteraction(); + void OnPreviewDismiss(); class NotificationItem { public: @@ -43,9 +46,11 @@ namespace Pinetime { Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController); ~NotificationItem(); + bool IsRunning() const { return running; } + void OnCallButtonEvent(lv_obj_t*, lv_event_t event); private: diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp index 1fb25085..dc973957 100644 --- a/src/displayapp/screens/Paddle.cpp +++ b/src/displayapp/screens/Paddle.cpp @@ -79,11 +79,11 @@ void Paddle::Refresh() { lv_label_set_text_fmt(points, "%04d", score); } -bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) { +bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents /*event*/) { return true; } -bool Paddle::OnTouchEvent(uint16_t x, uint16_t y) { +bool Paddle::OnTouchEvent(uint16_t /*x*/, uint16_t y) { // sets the center paddle pos. (30px offset) with the the y_coordinate of the finger // but clamp it such that the paddle never clips off screen if (y < 31) { diff --git a/src/displayapp/screens/Paddle.h b/src/displayapp/screens/Paddle.h index 3a30eee6..d62550c4 100644 --- a/src/displayapp/screens/Paddle.h +++ b/src/displayapp/screens/Paddle.h @@ -8,6 +8,7 @@ namespace Pinetime { namespace Components { class LittleVgl; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h index e72a2368..4cf134d2 100644 --- a/src/displayapp/screens/Screen.h +++ b/src/displayapp/screens/Screen.h @@ -7,13 +7,16 @@ namespace Pinetime { namespace Applications { class DisplayApp; + namespace Screens { template <class T> class DirtyValue { public: DirtyValue() = default; // Use NSDMI + explicit DirtyValue(T const& v) : value {v} { } // Use MIL and const-lvalue-ref + bool IsUpdated() { if (this->isUpdated) { this->isUpdated = false; @@ -21,10 +24,12 @@ namespace Pinetime { } return false; } + T const& Get() { this->isUpdated = false; return value; } // never expose a non-const lvalue-ref + DirtyValue& operator=(const T& other) { if (this->value != other) { this->value = other; @@ -46,6 +51,7 @@ namespace Pinetime { public: explicit Screen(DisplayApp* app) : app {app} { } + virtual ~Screen() = default; static void RefreshTaskCallback(lv_task_t* task); @@ -61,10 +67,11 @@ namespace Pinetime { /** @return false if the event hasn't been handled by the app, true if it has been handled */ // Returning true will cancel lvgl tap - virtual bool OnTouchEvent(TouchEvents event) { + virtual bool OnTouchEvent(TouchEvents /*event*/) { return false; } - virtual bool OnTouchEvent(uint16_t x, uint16_t y) { + + virtual bool OnTouchEvent(uint16_t /*x*/, uint16_t /*y*/) { return false; } diff --git a/src/displayapp/screens/ScreenList.h b/src/displayapp/screens/ScreenList.h index ad882948..6c9a2218 100644 --- a/src/displayapp/screens/ScreenList.h +++ b/src/displayapp/screens/ScreenList.h @@ -11,6 +11,7 @@ namespace Pinetime { namespace Screens { enum class ScreenListModes { UpDown, RightLeft, LongPress }; + template <size_t N> class ScreenList : public Screen { public: ScreenList(DisplayApp* app, diff --git a/src/displayapp/screens/Steps.h b/src/displayapp/screens/Steps.h index f109e0f2..32ad40bd 100644 --- a/src/displayapp/screens/Steps.h +++ b/src/displayapp/screens/Steps.h @@ -29,7 +29,6 @@ namespace Pinetime { uint32_t currentTripSteps = 0; lv_obj_t* lSteps; - lv_obj_t* lStepsIcon; lv_obj_t* stepsArc; lv_obj_t* resetBtn; lv_obj_t* resetButtonLabel; diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index 01c35195..b5b17347 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -99,7 +99,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() { std::unique_ptr<Screen> SystemInfo::CreateScreen2() { auto batteryPercent = batteryController.PercentRemaining(); - auto resetReason = [this]() { + const auto* resetReason = [this]() { switch (watchdog.ResetReason()) { case Drivers::Watchdog::ResetReasons::Watchdog: return "wtdg"; @@ -182,7 +182,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - auto& bleAddr = bleController.Address(); + const auto& bleAddr = bleController.Address(); lv_label_set_text_fmt(label, "#808080 BLE MAC#\n" " %02x:%02x:%02x:%02x:%02x:%02x" diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index a60076ed..681f9c9f 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -51,8 +51,9 @@ Tile::Tile(uint8_t screenID, uint8_t btIndex = 0; for (uint8_t i = 0; i < 6; i++) { - if (i == 3) + if (i == 3) { btnmMap[btIndex++] = "\n"; + } if (applications[i].application == Apps::None) { btnmMap[btIndex] = " "; } else { @@ -66,7 +67,7 @@ Tile::Tile(uint8_t screenID, btnm1 = lv_btnmatrix_create(lv_scr_act(), nullptr); lv_btnmatrix_set_map(btnm1, btnmMap); lv_obj_set_size(btnm1, LV_HOR_RES - 16, LV_VER_RES - 60); - lv_obj_align(btnm1, NULL, LV_ALIGN_CENTER, 0, 10); + lv_obj_align(btnm1, nullptr, LV_ALIGN_CENTER, 0, 10); lv_obj_set_style_local_radius(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, 20); lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_OPA_50); @@ -102,8 +103,9 @@ void Tile::UpdateScreen() { } void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) { - if (obj != btnm1) + if (obj != btnm1) { return; + } app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up); running = false; diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index a6b60a17..306281d7 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -26,7 +26,6 @@ namespace Pinetime::Applications::Screens { void UpdateMask(); Controllers::TimerController& timerController; - lv_obj_t* msecTime; lv_obj_t* btnPlayPause; lv_obj_t* txtPlayPause; @@ -40,7 +39,7 @@ namespace Pinetime::Applications::Screens { Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76); bool buttonPressing = false; - int maskPosition = 0; - TickType_t pressTime; + lv_coord_t maskPosition = 0; + TickType_t pressTime = 0; }; } diff --git a/src/displayapp/screens/Twos.h b/src/displayapp/screens/Twos.h index da935724..15017581 100644 --- a/src/displayapp/screens/Twos.h +++ b/src/displayapp/screens/Twos.h @@ -9,6 +9,7 @@ namespace Pinetime { bool merged = false; unsigned int value = 0; }; + namespace Screens { class Twos : public Screen { public: diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 5e5317ee..b36c29d3 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -61,9 +61,9 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, sMinute = 99; sSecond = 99; - lv_obj_t* bg_clock_img = lv_img_create(lv_scr_act(), NULL); + lv_obj_t* bg_clock_img = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src(bg_clock_img, &bg_clock); - lv_obj_align(bg_clock_img, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(bg_clock_img, nullptr, LV_ALIGN_CENTER, 0, 0); batteryIcon.Create(lv_scr_act()); lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); @@ -72,24 +72,24 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, lv_label_set_text_static(plugIcon, Symbols::plug); lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - notificationIcon = lv_label_create(lv_scr_act(), NULL); + 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_LIME); lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); - lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); // Date - Day / Week day - label_date_day = lv_label_create(lv_scr_act(), NULL); + label_date_day = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER); - lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0); + lv_obj_align(label_date_day, nullptr, LV_ALIGN_CENTER, 50, 0); - minute_body = lv_line_create(lv_scr_act(), NULL); - minute_body_trace = lv_line_create(lv_scr_act(), NULL); - hour_body = lv_line_create(lv_scr_act(), NULL); - hour_body_trace = lv_line_create(lv_scr_act(), NULL); - second_body = lv_line_create(lv_scr_act(), NULL); + minute_body = lv_line_create(lv_scr_act(), nullptr); + minute_body_trace = lv_line_create(lv_scr_act(), nullptr); + hour_body = lv_line_create(lv_scr_act(), nullptr); + hour_body_trace = lv_line_create(lv_scr_act(), nullptr); + second_body = lv_line_create(lv_scr_act(), nullptr); lv_style_init(&second_line_style); lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3); diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index 04d9e711..6e4e88a3 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -18,6 +18,7 @@ namespace Pinetime { class Ble; class NotificationManager; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp index bdae0d42..94b6a405 100644 --- a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp +++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp @@ -333,6 +333,7 @@ void WatchFaceCasioStyleG7710::Refresh() { lv_obj_realign(stepIcon); } } + bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem) { lfs_file file = {}; diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp index bd4e4ac8..ddf3cbcc 100644 --- a/src/displayapp/screens/WatchFaceInfineat.cpp +++ b/src/displayapp/screens/WatchFaceInfineat.cpp @@ -47,125 +47,40 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, font_bebas = lv_font_load("F:/fonts/bebas.bin"); } - // Black background covering the whole screen - background = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_obj_set_size(background, 240, 240); - lv_obj_align(background, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); - // Side Cover - line0 = lv_line_create(lv_scr_act(), nullptr); - line1 = lv_line_create(lv_scr_act(), nullptr); - line2 = lv_line_create(lv_scr_act(), nullptr); - line3 = lv_line_create(lv_scr_act(), nullptr); - line4 = lv_line_create(lv_scr_act(), nullptr); - line5 = lv_line_create(lv_scr_act(), nullptr); - line6 = lv_line_create(lv_scr_act(), nullptr); - line7 = lv_line_create(lv_scr_act(), nullptr); - line8 = lv_line_create(lv_scr_act(), nullptr); - lineBattery = lv_line_create(lv_scr_act(), nullptr); - - lv_style_init(&line0Style); - lv_style_set_line_width(&line0Style, LV_STATE_DEFAULT, 18); - lv_style_set_line_color(&line0Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines])); - lv_obj_add_style(line0, LV_LINE_PART_MAIN, &line0Style); - line0Points[0] = {30, 25}; - line0Points[1] = {68, -8}; - lv_line_set_points(line0, line0Points, 2); - - lv_style_init(&line1Style); - lv_style_set_line_width(&line1Style, LV_STATE_DEFAULT, 15); - lv_style_set_line_color(&line1Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 1])); - lv_obj_add_style(line1, LV_LINE_PART_MAIN, &line1Style); - line1Points[0] = {26, 167}; - line1Points[1] = {43, 216}; - lv_line_set_points(line1, line1Points, 2); - - lv_style_init(&line2Style); - lv_style_set_line_width(&line2Style, LV_STATE_DEFAULT, 14); - lv_style_set_line_color(&line2Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 2])); - lv_obj_add_style(line2, LV_LINE_PART_MAIN, &line2Style); - line2Points[0] = {27, 40}; - line2Points[1] = {27, 196}; - lv_line_set_points(line2, line2Points, 2); - - lv_style_init(&line3Style); - lv_style_set_line_width(&line3Style, LV_STATE_DEFAULT, 22); - lv_style_set_line_color(&line3Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 3])); - lv_obj_add_style(line3, LV_LINE_PART_MAIN, &line3Style); - line3Points[0] = {12, 182}; - line3Points[1] = {65, 249}; - lv_line_set_points(line3, line3Points, 2); - - lv_style_init(&line4Style); - lv_style_set_line_width(&line4Style, LV_STATE_DEFAULT, 20); - lv_style_set_line_color(&line4Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4])); - lv_obj_add_style(line4, LV_LINE_PART_MAIN, &line4Style); - line4Points[0] = {17, 99}; - line4Points[1] = {17, 144}; - lv_line_set_points(line4, line4Points, 2); + static constexpr lv_point_t linePoints[nLines][2] = {{{30, 25}, {68, -8}}, + {{26, 167}, {43, 216}}, + {{27, 40}, {27, 196}}, + {{12, 182}, {65, 249}}, + {{17, 99}, {17, 144}}, + {{14, 81}, {40, 127}}, + {{14, 163}, {40, 118}}, + {{-20, 124}, {25, -11}}, + {{-29, 89}, {27, 254}}}; - lv_style_init(&line5Style); - lv_style_set_line_width(&line5Style, LV_STATE_DEFAULT, 18); - lv_style_set_line_color(&line5Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 5])); - lv_obj_add_style(line5, LV_LINE_PART_MAIN, &line5Style); - line5Points[0] = {14, 81}; - line5Points[1] = {40, 127}; - lv_line_set_points(line5, line5Points, 2); + static constexpr lv_style_int_t lineWidths[nLines] = {18, 15, 14, 22, 20, 18, 18, 52, 48}; - lv_style_init(&line6Style); - lv_style_set_line_width(&line6Style, LV_STATE_DEFAULT, 18); - lv_style_set_line_color(&line6Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 6])); - lv_obj_add_style(line6, LV_LINE_PART_MAIN, &line6Style); - line6Points[0] = {14, 163}; - line6Points[1] = {40, 118}; - lv_line_set_points(line6, line6Points, 2); - - lv_style_init(&line7Style); - lv_style_set_line_width(&line7Style, LV_STATE_DEFAULT, 52); - lv_style_set_line_color(&line7Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 7])); - lv_obj_add_style(line7, LV_LINE_PART_MAIN, &line7Style); - line7Points[0] = {-20, 124}; - line7Points[1] = {25, -11}; - lv_line_set_points(line7, line7Points, 2); - - lv_style_init(&line8Style); - lv_style_set_line_width(&line8Style, LV_STATE_DEFAULT, 48); - lv_style_set_line_color(&line8Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 8])); - lv_obj_add_style(line8, LV_LINE_PART_MAIN, &line8Style); - line8Points[0] = {-29, 89}; - line8Points[1] = {27, 254}; - lv_line_set_points(line8, line8Points, 2); + for (int i = 0; i < nLines; i++) { + lines[i] = lv_line_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_line_width(lines[i], LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lineWidths[i]); + lv_obj_set_style_local_line_color(lines[i], + LV_LINE_PART_MAIN, + LV_STATE_DEFAULT, + lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + i])); + lv_line_set_points(lines[i], linePoints[i], 2); + } logoPine = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src(logoPine, "F:/images/pine_small.bin"); lv_obj_set_pos(logoPine, 15, 106); - lv_style_init(&lineBatteryStyle); - lv_style_set_line_width(&lineBatteryStyle, LV_STATE_DEFAULT, 24); - lv_style_set_line_color(&lineBatteryStyle, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4])); - lv_style_set_line_opa(&lineBatteryStyle, LV_STATE_DEFAULT, 190); - lv_obj_add_style(lineBattery, LV_LINE_PART_MAIN, &lineBatteryStyle); + lineBattery = lv_line_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_line_width(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 24); + lv_obj_set_style_local_line_color(lineBattery, + LV_LINE_PART_MAIN, + LV_STATE_DEFAULT, + lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4])); + lv_obj_set_style_local_line_opa(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 190); lineBatteryPoints[0] = {27, 105}; lineBatteryPoints[1] = {27, 106}; lv_line_set_points(lineBattery, lineBatteryPoints, 2); @@ -182,55 +97,30 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, if (!settingsController.GetInfineatShowSideCover()) { ToggleBatteryIndicatorColor(false); - lv_obj_set_hidden(line0, true); - lv_obj_set_hidden(line1, true); - lv_obj_set_hidden(line2, true); - lv_obj_set_hidden(line3, true); - lv_obj_set_hidden(line4, true); - lv_obj_set_hidden(line5, true); - lv_obj_set_hidden(line6, true); - lv_obj_set_hidden(line7, true); - lv_obj_set_hidden(line8, true); + for (auto& line : lines) { + lv_obj_set_hidden(line, true); + } } timeContainer = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_opa(timeContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - if (font_bebas != nullptr) { - lv_obj_set_size(timeContainer, 185, 185); - lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, -10); - } else { - lv_obj_set_size(timeContainer, 110, 145); - lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - } + lv_obj_set_size(timeContainer, 185, 185); + lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, -10); labelHour = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - lv_label_set_text(labelHour, "01"); - if (font_bebas != nullptr) { - lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); - lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 0); - } else { - lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 5); - } + lv_label_set_text_static(labelHour, "01"); + lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); + lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 0); labelMinutes = lv_label_create(lv_scr_act(), nullptr); - if (font_bebas != nullptr) { - lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); - } else { - lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - } - lv_label_set_text(labelMinutes, "00"); + lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); + lv_label_set_text_static(labelMinutes, "00"); lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0); labelTimeAmPm = lv_label_create(lv_scr_act(), nullptr); - if (font_teko != nullptr) { - lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - } else { - lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - } + lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - lv_label_set_text(labelTimeAmPm, ""); + lv_label_set_text_static(labelTimeAmPm, ""); lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 15); dateContainer = lv_obj_create(lv_scr_act(), nullptr); @@ -240,32 +130,24 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, labelDate = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - if (font_teko != nullptr) { - lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - } else { - lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - } + lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); lv_obj_align(labelDate, dateContainer, LV_ALIGN_IN_TOP_MID, 0, 0); - lv_label_set_text(labelDate, "Mon 01"); + lv_label_set_text_static(labelDate, "Mon 01"); 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(0x999999)); - lv_label_set_text(bleIcon, Symbols::bluetooth); + lv_label_set_text_static(bleIcon, Symbols::bluetooth); lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 0); stepValue = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - if (font_teko != nullptr) { - lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - } else { - lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - } + lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 10, 0); - lv_label_set_text(stepValue, "0"); + lv_label_set_text_static(stepValue, "0"); stepIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - lv_label_set_text(stepIcon, Symbols::shoe); + lv_label_set_text_static(stepIcon, Symbols::shoe); lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); // Setting buttons @@ -330,17 +212,6 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, WatchFaceInfineat::~WatchFaceInfineat() { lv_task_del(taskRefresh); - lv_style_reset(&line0Style); - lv_style_reset(&line1Style); - lv_style_reset(&line2Style); - lv_style_reset(&line3Style); - lv_style_reset(&line4Style); - lv_style_reset(&line5Style); - lv_style_reset(&line6Style); - lv_style_reset(&line7Style); - lv_style_reset(&line8Style); - lv_style_reset(&lineBatteryStyle); - if (font_bebas != nullptr) { lv_font_free(font_bebas); } @@ -398,15 +269,9 @@ void WatchFaceInfineat::UpdateSelected(lv_obj_t* object, lv_event_t event) { if (object == btnToggleCover) { settingsController.SetInfineatShowSideCover(!showSideCover); ToggleBatteryIndicatorColor(!showSideCover); - lv_obj_set_hidden(line0, showSideCover); - lv_obj_set_hidden(line1, showSideCover); - lv_obj_set_hidden(line2, showSideCover); - lv_obj_set_hidden(line3, showSideCover); - lv_obj_set_hidden(line4, showSideCover); - lv_obj_set_hidden(line5, showSideCover); - lv_obj_set_hidden(line6, showSideCover); - lv_obj_set_hidden(line7, showSideCover); - lv_obj_set_hidden(line8, showSideCover); + for (auto& line : lines) { + lv_obj_set_hidden(line, showSideCover); + } lv_obj_set_hidden(btnNextColor, showSideCover); lv_obj_set_hidden(btnPrevColor, showSideCover); const char* labelToggle = showSideCover ? "OFF" : "ON"; @@ -423,42 +288,12 @@ void WatchFaceInfineat::UpdateSelected(lv_obj_t* object, lv_event_t event) { settingsController.SetInfineatColorIndex(colorIndex); } if (object == btnNextColor || object == btnPrevColor) { - lv_obj_set_style_local_line_color(line0, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 0])); - lv_obj_set_style_local_line_color(line1, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 1])); - lv_obj_set_style_local_line_color(line2, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 2])); - lv_obj_set_style_local_line_color(line3, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 3])); - lv_obj_set_style_local_line_color(line4, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 4])); - lv_obj_set_style_local_line_color(line5, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 5])); - lv_obj_set_style_local_line_color(line6, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 6])); - lv_obj_set_style_local_line_color(line7, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 7])); - lv_obj_set_style_local_line_color(line8, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 8])); + for (int i = 0; i < nLines; i++) { + lv_obj_set_style_local_line_color(lines[i], + LV_LINE_PART_MAIN, + LV_STATE_DEFAULT, + lv_color_hex(infineatColors.orange[colorIndex * nLines + i])); + } lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, @@ -547,17 +382,13 @@ void WatchFaceInfineat::Refresh() { batteryPercentRemaining = batteryController.PercentRemaining(); isCharging = batteryController.IsCharging(); - // We store if battery and charging are updated before calling Get(), - // since Get() sets isUpdated to false. - bool isBatteryUpdated = batteryPercentRemaining.IsUpdated(); - bool isChargingUpdated = isCharging.IsUpdated(); - if (isCharging.Get()) { // Charging battery animation + if (batteryController.IsCharging()) { // Charging battery animation chargingBatteryPercent += 1; if (chargingBatteryPercent > 100) { chargingBatteryPercent = batteryPercentRemaining.Get(); } SetBatteryLevel(chargingBatteryPercent); - } else if (isChargingUpdated || isBatteryUpdated) { + } else if (isCharging.IsUpdated() || batteryPercentRemaining.IsUpdated()) { chargingBatteryPercent = batteryPercentRemaining.Get(); SetBatteryLevel(chargingBatteryPercent); } @@ -565,7 +396,7 @@ void WatchFaceInfineat::Refresh() { bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated()) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); + lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 3); } diff --git a/src/displayapp/screens/WatchFaceInfineat.h b/src/displayapp/screens/WatchFaceInfineat.h index 6c3c30ba..dfa0b38b 100644 --- a/src/displayapp/screens/WatchFaceInfineat.h +++ b/src/displayapp/screens/WatchFaceInfineat.h @@ -60,40 +60,9 @@ namespace Pinetime { DirtyValue<uint32_t> stepCount {}; DirtyValue<bool> notificationState {}; - lv_obj_t* background; - // Lines making up the side cover - lv_obj_t* line0; - lv_obj_t* line1; - lv_obj_t* line2; - lv_obj_t* line3; - lv_obj_t* line4; - lv_obj_t* line5; - lv_obj_t* line6; - lv_obj_t* line7; - lv_obj_t* line8; lv_obj_t* lineBattery; - lv_style_t line0Style; - lv_style_t line1Style; - lv_style_t line2Style; - lv_style_t line3Style; - lv_style_t line4Style; - lv_style_t line5Style; - lv_style_t line6Style; - lv_style_t line7Style; - lv_style_t line8Style; - lv_style_t lineBatteryStyle; - - lv_point_t line0Points[2]; - lv_point_t line1Points[2]; - lv_point_t line2Points[2]; - lv_point_t line3Points[2]; - lv_point_t line4Points[2]; - lv_point_t line5Points[2]; - lv_point_t line6Points[2]; - lv_point_t line7Points[2]; - lv_point_t line8Points[2]; lv_point_t lineBatteryPoints[2]; lv_obj_t* logoPine; @@ -118,6 +87,9 @@ namespace Pinetime { static constexpr int nLines = 9; static constexpr int nColors = 7; // must match number of colors in InfineatColors + + lv_obj_t* lines[nLines]; + struct InfineatColors { int orange[nLines] = {0xfd872b, 0xdb3316, 0x6f1000, 0xfd7a0a, 0xffffff, 0xffffff, 0xffffff, 0xe85102, 0xea1c00}; int blue[nLines] = {0xe7f8ff, 0x2232d0, 0x182a8b, 0xe7f8ff, 0xffffff, 0xffffff, 0xffffff, 0x5991ff, 0x1636ff}; diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.h b/src/displayapp/screens/WatchFacePineTimeStyle.h index 3085a1ae..b2cb0736 100644 --- a/src/displayapp/screens/WatchFacePineTimeStyle.h +++ b/src/displayapp/screens/WatchFacePineTimeStyle.h @@ -5,10 +5,10 @@ #include <cstdint> #include <memory> #include "displayapp/screens/Screen.h" +#include "displayapp/screens/BatteryIcon.h" #include "displayapp/Colors.h" #include "components/datetime/DateTimeController.h" #include "components/ble/BleController.h" -#include <displayapp/screens/BatteryIcon.h> namespace Pinetime { namespace Controllers { diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 92189737..d04cc517 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -30,8 +30,6 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, settingsController {settingsController}, heartRateController {heartRateController}, motionController {motionController} { - settingsController.SetClockFace(3); - batteryValue = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(batteryValue, true); lv_obj_align(batteryValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20); diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 1d0a83bd..ff067db8 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -27,7 +27,6 @@ using namespace Pinetime::Applications::Screens; Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::WeatherService& weather) : Screen(app), - dateTimeController {dateTimeController}, weatherService(weather), screens {app, 0, diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h index 34f95fce..21b05bd8 100644 --- a/src/displayapp/screens/Weather.h +++ b/src/displayapp/screens/Weather.h @@ -25,7 +25,6 @@ namespace Pinetime { private: bool running = true; - Pinetime::Controllers::DateTime& dateTimeController; Controllers::WeatherService& weatherService; ScreenList<5> screens; diff --git a/src/displayapp/screens/settings/SettingBluetooth.cpp b/src/displayapp/screens/settings/SettingBluetooth.cpp index c66be3e9..fd07be88 100644 --- a/src/displayapp/screens/settings/SettingBluetooth.cpp +++ b/src/displayapp/screens/settings/SettingBluetooth.cpp @@ -9,84 +9,52 @@ using namespace Pinetime::Applications::Screens; namespace { - void OnBluetoothDisabledEvent(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingBluetooth*>(obj->user_data); - screen->OnBluetoothDisabled(obj, event); - } + struct Option { + const char* name; + bool radioEnabled; + }; - void OnBluetoothEnabledEvent(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingBluetooth*>(obj->user_data); - screen->OnBluetoothEnabled(obj, event); - } + constexpr std::array<Option, 2> options = {{ + {"Enabled", true}, + {"Disabled", false}, + }}; + + std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() { + std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; + }; } SettingBluetooth::SettingBluetooth(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); - - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Bluetooth"); - lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); - lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); - - lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); - lv_label_set_text_static(icon, Symbols::bluetooth); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); - - cbEnabled = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbEnabled, " Enabled"); - cbEnabled->user_data = this; - lv_obj_set_event_cb(cbEnabled, OnBluetoothEnabledEvent); - SetRadioButtonStyle(cbEnabled); - - cbDisabled = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbDisabled, " Disabled"); - cbDisabled->user_data = this; - lv_obj_set_event_cb(cbDisabled, OnBluetoothDisabledEvent); - SetRadioButtonStyle(cbDisabled); - - if (settingsController.GetBleRadioEnabled()) { - lv_checkbox_set_checked(cbEnabled, true); - priorMode = true; - } else { - lv_checkbox_set_checked(cbDisabled, true); - priorMode = false; - } + : Screen(app), + checkboxList( + 0, + 1, + app, + "Bluetooth", + Symbols::bluetooth, + settingsController.GetBleRadioEnabled() ? 0 : 1, + [&settings = settingsController](uint32_t index) { + const bool priorMode = settings.GetBleRadioEnabled(); + const bool newMode = options[index].radioEnabled; + if (newMode != priorMode) { + settings.SetBleRadioEnabled(newMode); + } + }, + CreateOptionArray()) { } SettingBluetooth::~SettingBluetooth() { lv_obj_clean(lv_scr_act()); - // Do not call SaveSettings - see src/components/settings/Settings.h - if (priorMode != settingsController.GetBleRadioEnabled()) { - app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle); - } -} - -void SettingBluetooth::OnBluetoothDisabled(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - lv_checkbox_set_checked(cbEnabled, false); - lv_checkbox_set_checked(cbDisabled, true); - settingsController.SetBleRadioEnabled(false); - } -} - -void SettingBluetooth::OnBluetoothEnabled(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - lv_checkbox_set_checked(cbEnabled, true); - lv_checkbox_set_checked(cbDisabled, false); - settingsController.SetBleRadioEnabled(true); - } + // Pushing the message in the OnValueChanged function causes a freeze? + app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle); } diff --git a/src/displayapp/screens/settings/SettingBluetooth.h b/src/displayapp/screens/settings/SettingBluetooth.h index 12bb459a..611a0d5c 100644 --- a/src/displayapp/screens/settings/SettingBluetooth.h +++ b/src/displayapp/screens/settings/SettingBluetooth.h @@ -6,6 +6,7 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" namespace Pinetime { @@ -17,14 +18,8 @@ namespace Pinetime { SettingBluetooth(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingBluetooth() override; - void OnBluetoothEnabled(lv_obj_t* object, lv_event_t event); - void OnBluetoothDisabled(lv_obj_t* object, lv_event_t event); - private: - Controllers::Settings& settingsController; - lv_obj_t* cbEnabled; - lv_obj_t* cbDisabled; - bool priorMode; + CheckboxList checkboxList; }; } } diff --git a/src/displayapp/screens/settings/SettingChimes.cpp b/src/displayapp/screens/settings/SettingChimes.cpp index 7f519f75..6e12fb88 100644 --- a/src/displayapp/screens/settings/SettingChimes.cpp +++ b/src/displayapp/screens/settings/SettingChimes.cpp @@ -4,70 +4,62 @@ #include "displayapp/screens/Styles.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" +#include <array> using namespace Pinetime::Applications::Screens; namespace { - void event_handler(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingChimes*>(obj->user_data); - screen->UpdateSelected(obj, event); - } -} - -constexpr std::array<SettingChimes::Option, 3> SettingChimes::options; - -SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); + struct Option { + Pinetime::Controllers::Settings::ChimesOption chimesOption; + const char* name; + }; - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + constexpr std::array<Option, 3> options = {{ + {Pinetime::Controllers::Settings::ChimesOption::None, "Off"}, + {Pinetime::Controllers::Settings::ChimesOption::Hours, "Every hour"}, + {Pinetime::Controllers::Settings::ChimesOption::HalfHours, "Every 30 mins"}, + }}; - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Chimes"); - lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); - lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); - - lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); - lv_label_set_text_static(icon, Symbols::clock); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() { + std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; + } - for (unsigned int i = 0; i < options.size(); i++) { - cbOption[i] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbOption[i], options[i].name); - if (settingsController.GetChimeOption() == options[i].chimesOption) { - lv_checkbox_set_checked(cbOption[i], true); + uint32_t GetDefaultOption(Pinetime::Controllers::Settings::ChimesOption currentOption) { + for (size_t i = 0; i < options.size(); i++) { + if (options[i].chimesOption == currentOption) { + return i; + } } - cbOption[i]->user_data = this; - lv_obj_set_event_cb(cbOption[i], event_handler); - SetRadioButtonStyle(cbOption[i]); + return 0; } } -SettingChimes::~SettingChimes() { - lv_obj_clean(lv_scr_act()); - settingsController.SaveSettings(); +SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) + : Screen(app), + checkboxList( + 0, + 1, + app, + "Chimes", + Symbols::clock, + GetDefaultOption(settingsController.GetChimeOption()), + [&settings = settingsController](uint32_t index) { + settings.SetChimeOption(options[index].chimesOption); + settings.SaveSettings(); + }, + CreateOptionArray()) { } -void SettingChimes::UpdateSelected(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - for (uint8_t i = 0; i < options.size(); i++) { - if (object == cbOption[i]) { - lv_checkbox_set_checked(cbOption[i], true); - settingsController.SetChimeOption(options[i].chimesOption); - } else { - lv_checkbox_set_checked(cbOption[i], false); - } - } - } +SettingChimes::~SettingChimes() { + lv_obj_clean(lv_scr_act()); } diff --git a/src/displayapp/screens/settings/SettingChimes.h b/src/displayapp/screens/settings/SettingChimes.h index e48432c6..a306e81d 100644 --- a/src/displayapp/screens/settings/SettingChimes.h +++ b/src/displayapp/screens/settings/SettingChimes.h @@ -2,9 +2,10 @@ #include <cstdint> #include <lvgl/lvgl.h> + #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" -#include <array> +#include "displayapp/screens/CheckboxList.h" namespace Pinetime { @@ -19,19 +20,7 @@ namespace Pinetime { void UpdateSelected(lv_obj_t* object, lv_event_t event); private: - struct Option { - Controllers::Settings::ChimesOption chimesOption; - const char* name; - }; - static constexpr std::array<Option, 3> options = {{ - {Controllers::Settings::ChimesOption::None, " Off"}, - {Controllers::Settings::ChimesOption::Hours, " Every hour"}, - {Controllers::Settings::ChimesOption::HalfHours, " Every 30 mins"} - }}; - - std::array<lv_obj_t*, options.size()> cbOption; - - Controllers::Settings& settingsController; + CheckboxList checkboxList; }; } } diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp index 421aef02..c58f6fca 100644 --- a/src/displayapp/screens/settings/SettingSetDate.cpp +++ b/src/displayapp/screens/settings/SettingSetDate.cpp @@ -1,4 +1,5 @@ #include "displayapp/screens/settings/SettingSetDate.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" #include <lvgl/lvgl.h> #include <hal/nrf_rtc.h> #include <nrf_log.h> @@ -44,8 +45,11 @@ namespace { } } -SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController) - : Screen(app), dateTimeController {dateTimeController} { +SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime) + : Screen(app), dateTimeController {dateTimeController}, settingSetDateTime {settingSetDateTime} { + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Set current date"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); @@ -82,8 +86,6 @@ SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime lblSetTime = lv_label_create(btnSetTime, nullptr); lv_label_set_text_static(lblSetTime, "Set"); lv_obj_set_event_cb(btnSetTime, event_handler); - lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); } SettingSetDate::~SettingSetDate() { @@ -98,18 +100,14 @@ void SettingSetDate::HandleButtonPress() { dateTimeController.SetTime(yearValue, monthValue, dayValue, - 0, dateTimeController.Hours(), dateTimeController.Minutes(), dateTimeController.Seconds(), nrf_rtc_counter_get(portNRF_RTC_REG)); - lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); + settingSetDateTime.Advance(); } void SettingSetDate::CheckDay() { const int maxDay = MaximumDayOfMonth(monthCounter.GetValue(), yearCounter.GetValue()); dayCounter.SetMax(maxDay); - lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); - lv_obj_set_state(lblSetTime, LV_STATE_DEFAULT); } diff --git a/src/displayapp/screens/settings/SettingSetDate.h b/src/displayapp/screens/settings/SettingSetDate.h index a0ffc683..dfb0e0d2 100644 --- a/src/displayapp/screens/settings/SettingSetDate.h +++ b/src/displayapp/screens/settings/SettingSetDate.h @@ -5,13 +5,17 @@ #include "components/datetime/DateTimeController.h" #include "displayapp/screens/Screen.h" #include "displayapp/widgets/Counter.h" +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" namespace Pinetime { namespace Applications { namespace Screens { class SettingSetDate : public Screen { public: - SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController); + SettingSetDate(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime); ~SettingSetDate() override; void HandleButtonPress(); @@ -19,6 +23,7 @@ namespace Pinetime { private: Controllers::DateTime& dateTimeController; + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime; lv_obj_t* btnSetTime; lv_obj_t* lblSetTime; diff --git a/src/displayapp/screens/settings/SettingSetDateTime.cpp b/src/displayapp/screens/settings/SettingSetDateTime.cpp new file mode 100644 index 00000000..905a76ab --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetDateTime.cpp @@ -0,0 +1,54 @@ +#include "displayapp/screens/settings/SettingSetDateTime.h" +#include "displayapp/screens/settings/SettingSetDate.h" +#include "displayapp/screens/settings/SettingSetTime.h" +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/ScreenList.h" +#include "components/settings/Settings.h" +#include "displayapp/widgets/DotIndicator.h" + +using namespace Pinetime::Applications::Screens; + +bool SettingSetDateTime::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + return screens.OnTouchEvent(event); +} + +SettingSetDateTime::SettingSetDateTime(Pinetime::Applications::DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController) + : Screen(app), + dateTimeController {dateTimeController}, + settingsController {settingsController}, + screens {app, + 0, + {[this]() -> std::unique_ptr<Screen> { + return screenSetDate(); + }, + [this]() -> std::unique_ptr<Screen> { + return screenSetTime(); + }}, + Screens::ScreenListModes::UpDown} { +} + +std::unique_ptr<Screen> SettingSetDateTime::screenSetDate() { + Widgets::DotIndicator dotIndicator(0, 2); + dotIndicator.Create(); + return std::make_unique<Screens::SettingSetDate>(app, dateTimeController, *this); +} + +std::unique_ptr<Screen> SettingSetDateTime::screenSetTime() { + Widgets::DotIndicator dotIndicator(1, 2); + dotIndicator.Create(); + return std::make_unique<Screens::SettingSetTime>(app, dateTimeController, settingsController, *this); +} + +SettingSetDateTime::~SettingSetDateTime() { + lv_obj_clean(lv_scr_act()); +} + +void SettingSetDateTime::Advance() { + screens.OnTouchEvent(Pinetime::Applications::TouchEvents::SwipeUp); +} + +void SettingSetDateTime::Quit() { + running = false; +} diff --git a/src/displayapp/screens/settings/SettingSetDateTime.h b/src/displayapp/screens/settings/SettingSetDateTime.h new file mode 100644 index 00000000..dea283f8 --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetDateTime.h @@ -0,0 +1,32 @@ +#pragma once + +#include <cstdint> +#include <lvgl/lvgl.h> +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/ScreenList.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingSetDateTime : public Screen { + public: + SettingSetDateTime(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController); + ~SettingSetDateTime() override; + + bool OnTouchEvent(TouchEvents event) override; + void Advance(); + void Quit(); + + private: + Controllers::DateTime& dateTimeController; + Controllers::Settings& settingsController; + + ScreenList<2> screens; + std::unique_ptr<Screen> screenSetDate(); + std::unique_ptr<Screen> screenSetTime(); + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index e7d824fd..67ea7afa 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -18,6 +18,7 @@ namespace { screen->SetTime(); } } + void ValueChangedHandler(void* userData) { auto* screen = static_cast<SettingSetTime*>(userData); screen->UpdateScreen(); @@ -26,8 +27,9 @@ namespace { SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController) - : Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController} { + Pinetime::Controllers::Settings& settingsController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime) + : Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController}, settingSetDateTime {settingSetDateTime} { lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Set current time"); @@ -74,8 +76,6 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler); UpdateScreen(); - lv_obj_set_state(btnSetTime, LV_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); } SettingSetTime::~SettingSetTime() { @@ -90,8 +90,6 @@ void SettingSetTime::UpdateScreen() { lv_label_set_text_static(lblampm, "AM"); } } - lv_obj_set_state(btnSetTime, LV_STATE_DEFAULT); - lv_obj_set_state(lblSetTime, LV_STATE_DEFAULT); } void SettingSetTime::SetTime() { @@ -101,11 +99,9 @@ void SettingSetTime::SetTime() { dateTimeController.SetTime(dateTimeController.Year(), static_cast<uint8_t>(dateTimeController.Month()), dateTimeController.Day(), - static_cast<uint8_t>(dateTimeController.DayOfWeek()), static_cast<uint8_t>(hoursValue), static_cast<uint8_t>(minutesValue), 0, nrf_rtc_counter_get(portNRF_RTC_REG)); - lv_obj_set_state(btnSetTime, LV_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); + settingSetDateTime.Quit(); } diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index b61962c1..edd89b16 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -6,6 +6,8 @@ #include "components/settings/Settings.h" #include "displayapp/widgets/Counter.h" #include "displayapp/screens/Screen.h" +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" namespace Pinetime { namespace Applications { @@ -14,7 +16,8 @@ namespace Pinetime { public: SettingSetTime(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController); + Pinetime::Controllers::Settings& settingsController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime); ~SettingSetTime() override; void SetTime(); @@ -23,6 +26,7 @@ namespace Pinetime { private: Controllers::DateTime& dateTimeController; Controllers::Settings& settingsController; + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime; lv_obj_t* lblampm; lv_obj_t* btnSetTime; diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.cpp b/src/displayapp/screens/settings/SettingShakeThreshold.cpp index de46f7de..e7edee9a 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.cpp +++ b/src/displayapp/screens/settings/SettingShakeThreshold.cpp @@ -57,7 +57,7 @@ SettingShakeThreshold::SettingShakeThreshold(DisplayApp* app, lv_obj_set_width(calButton, 200); lv_obj_align(calButton, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_btn_set_checkable(calButton, true); - calLabel = lv_label_create(calButton, NULL); + calLabel = lv_label_create(calButton, nullptr); lv_label_set_text_static(calLabel, "Calibrate"); lv_arc_set_value(positionArc, settingsController.GetShakeThreshold()); @@ -102,7 +102,7 @@ void SettingShakeThreshold::Refresh() { } if (xTaskGetTickCount() - vCalTime > pdMS_TO_TICKS(7500)) { lv_btn_set_state(calButton, LV_STATE_DEFAULT); - lv_event_send(calButton, LV_EVENT_VALUE_CHANGED, NULL); + lv_event_send(calButton, LV_EVENT_VALUE_CHANGED, nullptr); } } if (motionController.currentShakeSpeed() - 300 > lv_arc_get_value(animArc)) { diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.h b/src/displayapp/screens/settings/SettingShakeThreshold.h index 43319468..d0979fa6 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.h +++ b/src/displayapp/screens/settings/SettingShakeThreshold.h @@ -6,6 +6,7 @@ #include "displayapp/screens/Screen.h" #include <components/motion/MotionController.h> #include "systemtask/SystemTask.h" + namespace Pinetime { namespace Applications { diff --git a/src/displayapp/screens/settings/SettingTimeFormat.cpp b/src/displayapp/screens/settings/SettingTimeFormat.cpp index 5502794b..824a10b2 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.cpp +++ b/src/displayapp/screens/settings/SettingTimeFormat.cpp @@ -8,76 +8,56 @@ using namespace Pinetime::Applications::Screens; namespace { - void event_handler(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingTimeFormat*>(obj->user_data); - screen->UpdateSelected(obj, event); - } -} - -constexpr std::array<const char*, 2> SettingTimeFormat::options; - -SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + struct Option { + Pinetime::Controllers::Settings::ClockType clockType; + const char* name; + }; - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); + constexpr std::array<Option, 2> options = {{ + {Pinetime::Controllers::Settings::ClockType::H12, "12-hour"}, + {Pinetime::Controllers::Settings::ClockType::H24, "24-hour"}, + }}; - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Time format"); - lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); - lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); - - lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); - lv_label_set_text_static(icon, Symbols::clock); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); - - for (unsigned int i = 0; i < options.size(); i++) { - cbOption[i] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbOption[i], options[i]); - cbOption[i]->user_data = this; - lv_obj_set_event_cb(cbOption[i], event_handler); - SetRadioButtonStyle(cbOption[i]); + std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() { + std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; } - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - lv_checkbox_set_checked(cbOption[0], true); - } else if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - lv_checkbox_set_checked(cbOption[1], true); + uint32_t GetDefaultOption(Pinetime::Controllers::Settings::ClockType currentOption) { + for (size_t i = 0; i < options.size(); i++) { + if (options[i].clockType == currentOption) { + return i; + } + } + return 0; } } -SettingTimeFormat::~SettingTimeFormat() { - lv_obj_clean(lv_scr_act()); - settingsController.SaveSettings(); +SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) + : Screen(app), + checkboxList( + 0, + 1, + app, + "Time format", + Symbols::clock, + GetDefaultOption(settingsController.GetClockType()), + [&settings = settingsController](uint32_t index) { + settings.SetClockType(options[index].clockType); + settings.SaveSettings(); + }, + CreateOptionArray()) { } -void SettingTimeFormat::UpdateSelected(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - for (unsigned int i = 0; i < options.size(); i++) { - if (object == cbOption[i]) { - lv_checkbox_set_checked(cbOption[i], true); - - if (i == 0) { - settingsController.SetClockType(Controllers::Settings::ClockType::H12); - }; - if (i == 1) { - settingsController.SetClockType(Controllers::Settings::ClockType::H24); - }; - - } else { - lv_checkbox_set_checked(cbOption[i], false); - } - } - } +SettingTimeFormat::~SettingTimeFormat() { + lv_obj_clean(lv_scr_act()); } diff --git a/src/displayapp/screens/settings/SettingTimeFormat.h b/src/displayapp/screens/settings/SettingTimeFormat.h index 01ca2c9b..de37f43e 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.h +++ b/src/displayapp/screens/settings/SettingTimeFormat.h @@ -6,6 +6,7 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" namespace Pinetime { @@ -17,12 +18,8 @@ namespace Pinetime { SettingTimeFormat(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingTimeFormat() override; - void UpdateSelected(lv_obj_t* object, lv_event_t event); - private: - static constexpr std::array<const char*, 2> options = {"12-hour", "24-hour"}; - Controllers::Settings& settingsController; - lv_obj_t* cbOption[options.size()]; + CheckboxList checkboxList; }; } } diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp index 59275e2f..620fe6e8 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.cpp +++ b/src/displayapp/screens/settings/SettingWakeUp.cpp @@ -4,19 +4,23 @@ #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" #include "components/settings/Settings.h" +#include "displayapp/screens/Styles.h" using namespace Pinetime::Applications::Screens; +constexpr std::array<SettingWakeUp::Option, 4> SettingWakeUp::options; + namespace { void event_handler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast<SettingWakeUp*>(obj->user_data); - screen->UpdateSelected(obj, event); + if (event == LV_EVENT_VALUE_CHANGED) { + screen->UpdateSelected(obj); + } } } 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); @@ -40,39 +44,15 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime:: 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], "Single Tap"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - 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.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - 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.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text_static(cbOption[optionsTotal], "Shake Wake"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); + for (unsigned int i = 0; i < options.size(); i++) { + cbOption[i] = lv_checkbox_create(container1, nullptr); + lv_checkbox_set_text(cbOption[i], options[i].name); + if (settingsController.isWakeUpModeOn(static_cast<Controllers::Settings::WakeUpMode>(i))) { + lv_checkbox_set_checked(cbOption[i], true); + } + cbOption[i]->user_data = this; + lv_obj_set_event_cb(cbOption[i], event_handler); } - optionsTotal++; } SettingWakeUp::~SettingWakeUp() { @@ -80,32 +60,21 @@ SettingWakeUp::~SettingWakeUp() { settingsController.SaveSettings(); } -void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) { - using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode; - if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) { - ignoringEvents = true; - - // 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]); +void SettingWakeUp::UpdateSelected(lv_obj_t* object) { + // Find the index of the checkbox that triggered the event + for (size_t i = 0; i < options.size(); i++) { + if (cbOption[i] == object) { + bool currentState = settingsController.isWakeUpModeOn(options[i].wakeUpMode); + settingsController.setWakeUpMode(options[i].wakeUpMode, !currentState); + break; } + } - ignoringEvents = false; + // 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 (size_t i = 0; i < options.size(); ++i) { + lv_checkbox_set_checked(cbOption[i], modes[i]); } } diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h index cd244ae5..2a4e7509 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.h +++ b/src/displayapp/screens/settings/SettingWakeUp.h @@ -1,5 +1,6 @@ #pragma once +#include <array> #include <cstdint> #include <lvgl/lvgl.h> #include "components/settings/Settings.h" @@ -15,17 +16,23 @@ namespace Pinetime { SettingWakeUp(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingWakeUp() override; - void UpdateSelected(lv_obj_t* object, lv_event_t event); + void UpdateSelected(lv_obj_t* object); private: + struct Option { + Controllers::Settings::WakeUpMode wakeUpMode; + const char* name; + }; + Controllers::Settings& settingsController; - uint8_t optionsTotal; - lv_obj_t* cbOption[5]; - // When UpdateSelected is called, it uses lv_checkbox_set_checked, - // which can cause extra events to be fired, - // which might trigger UpdateSelected again, causing a loop. - // This variable is used as a mutex to prevent that. - bool ignoringEvents; + static constexpr std::array<Option, 4> options = {{ + {Controllers::Settings::WakeUpMode::SingleTap, "Single Tap"}, + {Controllers::Settings::WakeUpMode::DoubleTap, "Double Tap"}, + {Controllers::Settings::WakeUpMode::RaiseWrist, "Raise Wrist"}, + {Controllers::Settings::WakeUpMode::Shake, "Shake Wake"}, + }}; + + lv_obj_t* cbOption[options.size()]; }; } } diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 217f97b8..da32b5ee 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -1,32 +1,31 @@ #include "displayapp/screens/settings/SettingWatchFace.h" #include <lvgl/lvgl.h> #include "displayapp/DisplayApp.h" -#include "displayapp/screens/CheckboxList.h" #include "displayapp/screens/Screen.h" #include "components/settings/Settings.h" -#include "displayapp/screens/WatchFaceInfineat.h" -#include "displayapp/screens/WatchFaceCasioStyleG7710.h" using namespace Pinetime::Applications::Screens; constexpr const char* SettingWatchFace::title; constexpr const char* SettingWatchFace::symbol; +auto SettingWatchFace::CreateScreenList() const { + std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens; + for (size_t i = 0; i < screens.size(); i++) { + screens[i] = [this, i]() -> std::unique_ptr<Screen> { + return CreateScreen(i); + }; + } + return screens; +} + SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::FS& filesystem) : Screen(app), settingsController {settingsController}, filesystem {filesystem}, - screens {app, - 0, - {[this]() -> std::unique_ptr<Screen> { - return CreateScreen1(); - }, - [this]() -> std::unique_ptr<Screen> { - return CreateScreen2(); - }}, - Screens::ScreenListModes::UpDown} { + screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} { } SettingWatchFace::~SettingWatchFace() { @@ -37,32 +36,15 @@ bool SettingWatchFace::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } -std::unique_ptr<Screen> SettingWatchFace::CreateScreen1() { - std::array<Screens::CheckboxList::Item, 4> watchfaces { - {{"Digital face", true}, {"Analog face", true}, {"PineTimeStyle", true}, {"Terminal", true}}}; - return std::make_unique<Screens::CheckboxList>( - 0, - 2, - app, - title, - symbol, - settingsController.GetClockFace(), - [&settings = settingsController](uint32_t clockFace) { - settings.SetClockFace(clockFace); - settings.SaveSettings(); - }, - watchfaces); -} +std::unique_ptr<Screen> SettingWatchFace::CreateScreen(unsigned int screenNum) const { + std::array<Screens::CheckboxList::Item, settingsPerScreen> watchfacesOnThisScreen; + for (int i = 0; i < settingsPerScreen; i++) { + watchfacesOnThisScreen[i] = watchfaces[screenNum * settingsPerScreen + i]; + } -std::unique_ptr<Screen> SettingWatchFace::CreateScreen2() { - std::array<Screens::CheckboxList::Item, 4> watchfaces { - {{"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)}, - {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)}, - {"", false}, - {"", false}}}; return std::make_unique<Screens::CheckboxList>( - 1, - 2, + screenNum, + nScreens, app, title, symbol, @@ -71,5 +53,5 @@ std::unique_ptr<Screen> SettingWatchFace::CreateScreen2() { settings.SetClockFace(clockFace); settings.SaveSettings(); }, - watchfaces); + watchfacesOnThisScreen); } diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 158397f8..7b8cdcdc 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -8,6 +8,9 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/screens/CheckboxList.h" +#include "displayapp/screens/WatchFaceInfineat.h" +#include "displayapp/screens/WatchFaceCasioStyleG7710.h" namespace Pinetime { @@ -22,14 +25,30 @@ namespace Pinetime { bool OnTouchEvent(TouchEvents event) override; private: + auto CreateScreenList() const; + std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const; + Controllers::Settings& settingsController; Pinetime::Controllers::FS& filesystem; - ScreenList<2> screens; static constexpr const char* title = "Watch face"; static constexpr const char* symbol = Symbols::home; - std::unique_ptr<Screen> CreateScreen1(); - std::unique_ptr<Screen> CreateScreen2(); + + static constexpr int settingsPerScreen = 4; + + // Increment this when more space is needed + static constexpr int nScreens = 2; + + std::array<Screens::CheckboxList::Item, settingsPerScreen * nScreens> watchfaces { + {{"Digital face", true}, + {"Analog face", true}, + {"PineTimeStyle", true}, + {"Terminal", true}, + {"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)}, + {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)}, + {"", false}, + {"", false}}}; + ScreenList<nScreens> screens; }; } } diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index a86db44f..b88c13b7 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -28,7 +28,7 @@ namespace Pinetime { static constexpr int entriesPerScreen = 4; // Increment this when more space is needed - static constexpr int nScreens = 4; + static constexpr int nScreens = 3; static constexpr std::array<List::Applications, entriesPerScreen * nScreens> entries {{ {Symbols::sun, "Display", Apps::SettingDisplay}, @@ -37,19 +37,20 @@ namespace Pinetime { {Symbols::home, "Watch face", Apps::SettingWatchFace}, {Symbols::shoe, "Steps", Apps::SettingSteps}, - {Symbols::clock, "Set date", Apps::SettingSetDate}, - {Symbols::clock, "Set time", Apps::SettingSetTime}, + {Symbols::clock, "Date&Time", Apps::SettingSetDateTime}, {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, - {Symbols::clock, "Chimes", Apps::SettingChimes}, + {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, - {Symbols::list, "About", Apps::SysInfo}, - {Symbols::none, "None", Apps::None}, - {Symbols::none, "None", Apps::None}, - {Symbols::none, "None", Apps::None}, + + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + }}; ScreenList<nScreens> screens; }; diff --git a/src/displayapp/widgets/Counter.cpp b/src/displayapp/widgets/Counter.cpp index e95178ec..b486e372 100644 --- a/src/displayapp/widgets/Counter.cpp +++ b/src/displayapp/widgets/Counter.cpp @@ -18,6 +18,7 @@ namespace { widget->DownBtnPressed(); } } + constexpr int digitCount(int number) { int digitCount = 0; while (number > 0) { @@ -28,7 +29,7 @@ namespace { } } -Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, font {font}, leadingZeroCount {digitCount(max)} { +Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, leadingZeroCount {digitCount(max)}, font {font} { } void Counter::UpBtnPressed() { @@ -67,6 +68,7 @@ void Counter::HideControls() { lv_obj_set_hidden(lowerLine, true); lv_obj_set_style_local_bg_opa(counterContainer, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); } + void Counter::ShowControls() { lv_obj_set_hidden(upBtn, false); lv_obj_set_hidden(downBtn, false); diff --git a/src/displayapp/widgets/DotIndicator.cpp b/src/displayapp/widgets/DotIndicator.cpp new file mode 100644 index 00000000..209b43bd --- /dev/null +++ b/src/displayapp/widgets/DotIndicator.cpp @@ -0,0 +1,28 @@ +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Widgets; + +DotIndicator::DotIndicator(uint8_t nCurrentScreen, uint8_t nScreens) : nCurrentScreen {nCurrentScreen}, nScreens {nScreens} { +} + +void DotIndicator::Create() { + lv_obj_t* dotIndicator[nScreens]; + static constexpr uint8_t dotSize = 12; + + lv_obj_t* container = lv_cont_create(lv_scr_act(), nullptr); + lv_cont_set_layout(container, LV_LAYOUT_COLUMN_LEFT); + lv_cont_set_fit(container, LV_FIT_TIGHT); + lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, dotSize); + lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + + for (int i = 0; i < nScreens; i++) { + dotIndicator[i] = lv_obj_create(container, nullptr); + lv_obj_set_size(dotIndicator[i], dotSize, dotSize); + lv_obj_set_style_local_bg_color(dotIndicator[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + } + + lv_obj_set_style_local_bg_color(dotIndicator[nCurrentScreen], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + + lv_obj_align(container, nullptr, LV_ALIGN_IN_RIGHT_MID, 0, 0); +} diff --git a/src/displayapp/widgets/DotIndicator.h b/src/displayapp/widgets/DotIndicator.h new file mode 100644 index 00000000..49cdca26 --- /dev/null +++ b/src/displayapp/widgets/DotIndicator.h @@ -0,0 +1,18 @@ +#pragma once +#include <lvgl/lvgl.h> + +namespace Pinetime { + namespace Applications { + namespace Widgets { + class DotIndicator { + public: + DotIndicator(uint8_t nCurrentScreen, uint8_t nScreens); + void Create(); + + private: + uint8_t nCurrentScreen; + uint8_t nScreens; + }; + } + } +} diff --git a/src/displayapp/widgets/StatusIcons.h b/src/displayapp/widgets/StatusIcons.h index f4a30a80..7d9e3ae3 100644 --- a/src/displayapp/widgets/StatusIcons.h +++ b/src/displayapp/widgets/StatusIcons.h @@ -15,9 +15,11 @@ namespace Pinetime { StatusIcons(Controllers::Battery& batteryController, Controllers::Ble& bleController); void Align(); void Create(); + lv_obj_t* GetObject() { return container; } + void Update(); private: diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp index 539cc8d1..84d76ab3 100644 --- a/src/drivers/Bma421.cpp +++ b/src/drivers/Bma421.cpp @@ -19,7 +19,7 @@ namespace { return 0; } - void user_delay(uint32_t period_us, void* intf_ptr) { + void user_delay(uint32_t period_us, void* /*intf_ptr*/) { nrf_delay_us(period_us); } } @@ -118,6 +118,7 @@ Bma421::Values Bma421::Process() { // 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}; } + bool Bma421::IsOk() const { return isOk; } @@ -133,6 +134,7 @@ void Bma421::SoftReset() { nrf_delay_ms(1); } } + Bma421::DeviceTypes Bma421::DeviceType() const { return deviceType; } diff --git a/src/drivers/Bma421.h b/src/drivers/Bma421.h index ac5c707f..fb832514 100644 --- a/src/drivers/Bma421.h +++ b/src/drivers/Bma421.h @@ -4,15 +4,18 @@ namespace Pinetime { namespace Drivers { class TwiMaster; + class Bma421 { public: enum class DeviceTypes : uint8_t { Unknown, BMA421, BMA425 }; + struct Values { uint32_t steps; int16_t x; int16_t y; int16_t z; }; + Bma421(TwiMaster& twiMaster, uint8_t twiAddress); Bma421(const Bma421&) = delete; Bma421& operator=(const Bma421&) = delete; diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h index 9d426c9d..c50bb733 100644 --- a/src/drivers/Cst816s.h +++ b/src/drivers/Cst816s.h @@ -16,6 +16,7 @@ namespace Pinetime { DoubleTap = 0x0B, LongPress = 0x0C }; + struct TouchInfos { uint16_t x = 0; uint16_t y = 0; @@ -38,9 +39,11 @@ namespace Pinetime { uint8_t GetChipId() const { return chipId; } + uint8_t GetVendorId() const { return vendorId; } + uint8_t GetFwVersion() const { return fwVersion; } diff --git a/src/drivers/DebugPins.cpp b/src/drivers/DebugPins.cpp index 4b2f0f16..6d24ca04 100644 --- a/src/drivers/DebugPins.cpp +++ b/src/drivers/DebugPins.cpp @@ -18,6 +18,7 @@ void debugpins_init() { nrf_gpio_cfg_output(DebugPin4); nrf_gpio_pin_clear(DebugPin4); } + void debugpins_set(debugpins_pins pin) { nrf_gpio_pin_set(static_cast<uint32_t>(pin)); } @@ -33,6 +34,7 @@ void debugpins_pulse(debugpins_pins pin) { #else void debugpins_init() { } + void debugpins_set(debugpins_pins pin) { } diff --git a/src/drivers/DebugPins.h b/src/drivers/DebugPins.h deleted file mode 100644 index b30cd222..00000000 --- a/src/drivers/DebugPins.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -typedef enum { - DebugPin0 = 27, - DebugPin1 = 29, - DebugPin2 = 20, - DebugPin3 = 17, - DebugPin4 = 11, -} debugpins_pins; - -void debugpins_init(); -void debugpins_set(debugpins_pins pin); -void debugpins_clear(debugpins_pins pin); -void debugpins_pulse(debugpins_pins pin); - -#ifdef __cplusplus -} -#endif diff --git a/src/drivers/Hrs3300.cpp b/src/drivers/Hrs3300.cpp index ec620af2..6c47ae28 100644 --- a/src/drivers/Hrs3300.cpp +++ b/src/drivers/Hrs3300.cpp @@ -13,6 +13,7 @@ #include <nrf_log.h> using namespace Pinetime::Drivers; + /** Driver for the HRS3300 heart rate sensor. * Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/drivers/hrs3300.py */ diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 38f72fee..234884ab 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -163,10 +163,7 @@ void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile spiBaseAddress->EVENTS_END = 0; } -void SpiMaster::PrepareRx(const volatile uint32_t cmdAddress, - const volatile size_t cmdSize, - const volatile uint32_t bufferAddress, - const volatile size_t size) { +void SpiMaster::PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size) { spiBaseAddress->TXD.PTR = 0; spiBaseAddress->TXD.MAXCNT = 0; spiBaseAddress->TXD.LIST = 0; @@ -234,7 +231,7 @@ bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data while (spiBaseAddress->EVENTS_END == 0) ; - PrepareRx((uint32_t) cmd, cmdSize, (uint32_t) data, dataSize); + PrepareRx((uint32_t) data, dataSize); spiBaseAddress->TASKS_START = 1; while (spiBaseAddress->EVENTS_END == 0) diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 5ea624f2..8b698c57 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -14,6 +14,7 @@ namespace Pinetime { enum class BitOrder : uint8_t { Msb_Lsb, Lsb_Msb }; enum class Modes : uint8_t { Mode0, Mode1, Mode2, Mode3 }; enum class Frequencies : uint8_t { Freq8Mhz }; + struct Parameters { BitOrder bitOrder; Modes mode; @@ -45,10 +46,7 @@ namespace Pinetime { void SetupWorkaroundForFtpan58(NRF_SPIM_Type* spim, uint32_t ppi_channel, uint32_t gpiote_channel); void DisableWorkaroundForFtpan58(NRF_SPIM_Type* spim, uint32_t ppi_channel, uint32_t gpiote_channel); void PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size); - void PrepareRx(const volatile uint32_t cmdAddress, - const volatile size_t cmdSize, - const volatile uint32_t bufferAddress, - const volatile size_t size); + void PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size); NRF_SPIM_Type* spiBaseAddress; uint8_t pinCsn; diff --git a/src/drivers/SpiNorFlash.h b/src/drivers/SpiNorFlash.h index ad4d0907..8a063fea 100644 --- a/src/drivers/SpiNorFlash.h +++ b/src/drivers/SpiNorFlash.h @@ -5,6 +5,7 @@ namespace Pinetime { namespace Drivers { class Spi; + class SpiNorFlash { public: explicit SpiNorFlash(Spi& spi); diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 8c2ac093..8a1bdfca 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -5,6 +5,7 @@ namespace Pinetime { namespace Drivers { class Spi; + class St7789 { public: explicit St7789(Spi& spi, uint8_t pinDataCommand); diff --git a/src/drivers/Watchdog.h b/src/drivers/Watchdog.h index 03807d61..22aa9df6 100644 --- a/src/drivers/Watchdog.h +++ b/src/drivers/Watchdog.h @@ -9,9 +9,11 @@ namespace Pinetime { void Setup(uint8_t timeoutSeconds); void Start(); void Kick(); + ResetReasons ResetReason() const { return resetReason; } + static const char* ResetReasonToString(ResetReasons reason); private: @@ -23,6 +25,7 @@ namespace Pinetime { public: WatchdogView(const Watchdog& watchdog) : watchdog {watchdog} { } + Watchdog::ResetReasons ResetReason() const { return watchdog.ResetReason(); } diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index bc227624..50833ab2 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -6,15 +6,16 @@ using namespace Pinetime::Applications; HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller) - : heartRateSensor {heartRateSensor}, controller {controller}, ppg {} { + : heartRateSensor {heartRateSensor}, controller {controller} { } void HeartRateTask::Start() { messageQueue = xQueueCreate(10, 1); controller.SetHeartRateTask(this); - if (pdPASS != xTaskCreate(HeartRateTask::Process, "Heartrate", 500, this, 0, &taskHandle)) + if (pdPASS != xTaskCreate(HeartRateTask::Process, "Heartrate", 500, this, 0, &taskHandle)) { APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); + } } void HeartRateTask::Process(void* instance) { @@ -25,17 +26,19 @@ void HeartRateTask::Process(void* instance) { void HeartRateTask::Work() { int lastBpm = 0; while (true) { - Messages msg; - uint32_t delay; + auto delay = portMAX_DELAY; if (state == States::Running) { - if (measurementStarted) + if (measurementStarted) { delay = 40; - else + } else { delay = 100; - } else + } + } else { delay = portMAX_DELAY; + } - if (xQueueReceive(messageQueue, &msg, delay)) { + Messages msg; + if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { switch (msg) { case Messages::GoToSleep: StopMeasurement(); @@ -49,15 +52,17 @@ void HeartRateTask::Work() { } break; case Messages::StartMeasurement: - if (measurementStarted) + if (measurementStarted) { break; + } lastBpm = 0; StartMeasurement(); measurementStarted = true; break; case Messages::StopMeasurement: - if (!measurementStarted) + if (!measurementStarted) { break; + } StopMeasurement(); measurementStarted = false; break; @@ -68,8 +73,9 @@ void HeartRateTask::Work() { ppg.Preprocess(static_cast<float>(heartRateSensor.ReadHrs())); auto bpm = ppg.HeartRate(); - if (lastBpm == 0 && bpm == 0) + if (lastBpm == 0 && bpm == 0) { controller.Update(Controllers::HeartRateController::States::NotEnoughData, 0); + } if (bpm != 0) { lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, lastBpm); @@ -79,10 +85,9 @@ void HeartRateTask::Work() { } void HeartRateTask::PushMessage(HeartRateTask::Messages msg) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(messageQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { + if (xHigherPriorityTaskWoken == pdTRUE) { /* Actual macro used here is port specific. */ // TODO : should I do something here? } @@ -91,7 +96,7 @@ void HeartRateTask::PushMessage(HeartRateTask::Messages msg) { void HeartRateTask::StartMeasurement() { heartRateSensor.Enable(); vTaskDelay(100); - ppg.SetOffset(static_cast<float>(heartRateSensor.ReadHrs())); + ppg.SetOffset(heartRateSensor.ReadHrs()); } void HeartRateTask::StopMeasurement() { diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 0796dc74..5bbfb9fb 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -8,9 +8,11 @@ namespace Pinetime { namespace Drivers { class Hrs3300; } + namespace Controllers { class HeartRateController; } + namespace Applications { class HeartRateTask { public: diff --git a/src/logging/DummyLogger.h b/src/logging/DummyLogger.h index 1b050b37..53590b6f 100644 --- a/src/logging/DummyLogger.h +++ b/src/logging/DummyLogger.h @@ -7,6 +7,7 @@ namespace Pinetime { public: void Init() override { } + void Resume() override { } }; diff --git a/src/main.cpp b/src/main.cpp index ad7a07dc..b205f1e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,7 +45,6 @@ #include "drivers/Cst816s.h" #include "drivers/PinMap.h" #include "systemtask/SystemTask.h" -#include "drivers/PinMap.h" #include "touchhandler/TouchHandler.h" #include "buttonhandler/ButtonHandler.h" @@ -210,29 +209,29 @@ void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) { } } -static void (*radio_isr_addr)(void); -static void (*rng_isr_addr)(void); -static void (*rtc0_isr_addr)(void); +static void (*radio_isr_addr)(); +static void (*rng_isr_addr)(); +static void (*rtc0_isr_addr)(); /* Some interrupt handlers required for NimBLE radio driver */ extern "C" { void RADIO_IRQHandler(void) { - ((void (*)(void)) radio_isr_addr)(); + ((void (*)()) radio_isr_addr)(); } void RNG_IRQHandler(void) { - ((void (*)(void)) rng_isr_addr)(); + ((void (*)()) rng_isr_addr)(); } void RTC0_IRQHandler(void) { - ((void (*)(void)) rtc0_isr_addr)(); + ((void (*)()) rtc0_isr_addr)(); } void WDT_IRQHandler(void) { nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT); } -void npl_freertos_hw_set_isr(int irqn, void (*addr)(void)) { +void npl_freertos_hw_set_isr(int irqn, void (*addr)()) { switch (irqn) { case RADIO_IRQn: radio_isr_addr = addr; @@ -243,6 +242,8 @@ void npl_freertos_hw_set_isr(int irqn, void (*addr)(void)) { case RTC0_IRQn: rtc0_isr_addr = addr; break; + default: + break; } } @@ -253,7 +254,7 @@ uint32_t npl_freertos_hw_enter_critical(void) { } void npl_freertos_hw_exit_critical(uint32_t ctx) { - if (!ctx) { + if (ctx == 0) { __enable_irq(); } } @@ -265,15 +266,14 @@ struct ble_npl_eventq* nimble_port_get_dflt_eventq(void) { } void nimble_port_run(void) { - struct ble_npl_event* ev; - - while (1) { - ev = ble_npl_eventq_get(&g_eventq_dflt, BLE_NPL_TIME_FOREVER); - ble_npl_event_run(ev); + struct ble_npl_event* event; + while (true) { + event = ble_npl_eventq_get(&g_eventq_dflt, BLE_NPL_TIME_FOREVER); + ble_npl_event_run(event); } } -void BleHost(void*) { +void BleHost(void* /*unused*/) { nimble_port_run(); } @@ -285,8 +285,7 @@ void nimble_port_init(void) { ble_hs_init(); ble_store_ram_init(); - int res; - res = hal_timer_init(5, NULL); + int res = hal_timer_init(5, nullptr); ASSERT(res == 0); res = os_cputime_init(32768); ASSERT(res == 0); @@ -301,17 +300,17 @@ void nimble_port_ll_task_func(void* args) { } } -void calibrate_lf_clock_rc(nrf_drv_clock_evt_type_t event) { +void calibrate_lf_clock_rc(nrf_drv_clock_evt_type_t /*event*/) { // 16 * 0.25s = 4s calibration cycle // Not recursive, call is deferred via internal calibration timer nrf_drv_clock_calibration_start(16, calibrate_lf_clock_rc); } -int main(void) { +int main() { logger.Init(); nrf_drv_clock_init(); - nrf_drv_clock_lfclk_request(NULL); + nrf_drv_clock_lfclk_request(nullptr); // When loading the firmware via the Wasp-OS reloader-factory, which uses the used internal LF RC oscillator, // the LF clock has to be explicitly restarted because InfiniTime uses the external crystal oscillator if available. diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 27a79d9c..d6f8d49b 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -81,7 +81,8 @@ void RefreshWatchdog() { } uint8_t displayBuffer[displayWidth * bytesPerPixel]; -void Process(void* instance) { + +void Process(void* /*instance*/) { RefreshWatchdog(); APP_GPIOTE_INIT(2); diff --git a/src/resources/fonts.json b/src/resources/fonts.json index a270e6a2..c4a63349 100644 --- a/src/resources/fonts.json +++ b/src/resources/fonts.json @@ -3,7 +3,7 @@ "sources": [ { "file": "fonts/Teko-Light.ttf", - "symbols": "0123456789:/ampMonTueWdhFriSt " + "symbols": "0123456789:/APMonTueWdhFriSat " } ], "bpp": 1, diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index 7a46e060..b7fee8a5 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -1,8 +1,9 @@ #pragma once +#include <cstdint> namespace Pinetime { namespace System { - enum class Messages { + enum class Messages : uint8_t { GoToSleep, GoToRunning, TouchWakeUp, @@ -29,6 +30,7 @@ namespace Pinetime { StopRinging, MeasureBatteryTimerExpired, BatteryPercentageUpdated, + LowBattery, StartFileTransfer, StopFileTransfer, BleRadioEnableToggle diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index ef631af7..73f573fa 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -18,6 +18,8 @@ #include "BootErrors.h" #include <memory> +#include <algorithm> +#include <cstring> using namespace Pinetime::System; @@ -30,14 +32,14 @@ namespace { void DimTimerCallback(TimerHandle_t xTimer) { NRF_LOG_INFO("DimTimerCallback"); - auto sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); + auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); sysTask->OnDim(); } void IdleTimerCallback(TimerHandle_t xTimer) { NRF_LOG_INFO("IdleTimerCallback"); - auto sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); + auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); sysTask->OnIdle(); } @@ -208,10 +210,9 @@ void SystemTask::Work() { while (true) { UpdateMotion(); - uint8_t msg; - if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) { - Messages message = static_cast<Messages>(msg); - switch (message) { + Messages msg; + if (xQueueReceive(systemTasksMsgQueue, &msg, 100) == pdTRUE) { + switch (msg) { case Messages::EnableSleeping: // Make sure that exiting an app doesn't enable sleeping, // if the exiting was caused by a firmware update @@ -348,7 +349,7 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); break; case Messages::HandleButtonEvent: { - Controllers::ButtonActions action; + Controllers::ButtonActions action = Controllers::ButtonActions::None; if (nrf_gpio_pin_read(Pinetime::PinMap::Button) == 0) { action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Release); } else { @@ -425,6 +426,16 @@ void SystemTask::Work() { case Messages::BatteryPercentageUpdated: nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); break; + case Messages::LowBattery: { + Pinetime::Controllers::NotificationManager::Notification notif; + constexpr char message[] = "Low Battery\0Charge your watch to prevent data loss.\0"; + constexpr size_t messageSize = std::min(sizeof(message), Pinetime::Controllers::NotificationManager::MaximumMessageSize()); + std::memcpy(notif.message.data(), message, messageSize); + notif.size = messageSize; + notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; + notificationManager.Push(std::move(notif)); + PushMessage(Messages::OnNewNotification); + } break; case Messages::OnPairing: if (state == SystemTaskState::Sleeping) { GoToRunning(); @@ -459,7 +470,7 @@ void SystemTask::Work() { uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); dateTimeController.UpdateTime(systick_counter); NoInit_BackUpTime = dateTimeController.CurrentDateTime(); - if (!nrf_gpio_pin_read(PinMap::Button)) { + if (nrf_gpio_pin_read(PinMap::Button) == 0) { watchdog.Kick(); } } @@ -552,10 +563,9 @@ void SystemTask::PushMessage(System::Messages msg) { } if (in_isr()) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { + if (xHigherPriorityTaskWoken == pdTRUE) { /* Actual macro used here is port specific. */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index d1e4a004..9c43b9b2 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -36,6 +36,7 @@ #include "systemtask/Messages.h" extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime; + namespace Pinetime { namespace Drivers { class Cst816S; @@ -45,11 +46,13 @@ namespace Pinetime { class TwiMaster; class Hrs3300; } + namespace Controllers { class Battery; class TouchHandler; class ButtonHandler; } + namespace System { class SystemTask { public: diff --git a/src/touchhandler/TouchHandler.h b/src/touchhandler/TouchHandler.h index 332041e5..afce2844 100644 --- a/src/touchhandler/TouchHandler.h +++ b/src/touchhandler/TouchHandler.h @@ -6,9 +6,11 @@ namespace Pinetime { namespace Components { class LittleVgl; } + namespace Drivers { class Cst816S; } + namespace Controllers { class TouchHandler { public: @@ -20,12 +22,15 @@ namespace Pinetime { bool IsTouching() const { return info.touching; } + uint8_t GetX() const { return info.x; } + uint8_t GetY() const { return info.y; } + Pinetime::Applications::TouchEvents GestureGet(); private: |
