From c2cf2a601a4d947ba0eab868db3756c6e70e3002 Mon Sep 17 00:00:00 2001 From: Adrian Date: Sat, 11 Nov 2023 06:52:55 +0100 Subject: [PATCH 1/4] Added Binary Watch Face --- src/displayapp/WatchFaces.h | 9 +- src/displayapp/screens/Clock.cpp | 14 + src/displayapp/screens/Clock.h | 1 + src/displayapp/screens/WatchFaceBinary.cpp | 245 ++++++++++++++++++ src/displayapp/screens/WatchFaceBinary.h | 73 ++++++ .../screens/settings/SettingWatchFace.h | 2 +- 6 files changed, 339 insertions(+), 5 deletions(-) create mode 100644 src/displayapp/screens/WatchFaceBinary.cpp create mode 100644 src/displayapp/screens/WatchFaceBinary.h diff --git a/src/displayapp/WatchFaces.h b/src/displayapp/WatchFaces.h index 2982347a..da0d7067 100644 --- a/src/displayapp/WatchFaces.h +++ b/src/displayapp/WatchFaces.h @@ -5,10 +5,11 @@ namespace Pinetime { enum class WatchFace : uint8_t { Digital = 0, Analog = 1, - PineTimeStyle = 2, - Terminal = 3, - Infineat = 4, - CasioStyleG7710 = 5, + Binary = 2, + PineTimeStyle = 3, + Terminal = 4, + Infineat = 5, + CasioStyleG7710 = 6, }; } } diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index 4219b090..3373da19 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -10,6 +10,7 @@ #include "displayapp/screens/WatchFaceDigital.h" #include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceInfineat.h" +#include "displayapp/screens/WatchFaceBinary.h" #include "displayapp/screens/WatchFaceAnalog.h" #include "displayapp/screens/WatchFacePineTimeStyle.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h" @@ -43,6 +44,9 @@ Clock::Clock(Controllers::DateTime& dateTimeController, case WatchFace::Analog: return WatchFaceAnalogScreen(); break; + case WatchFace::Binary: + return WatchFaceBinaryScreen(); + break; case WatchFace::PineTimeStyle: return WatchFacePineTimeStyleScreen(); break; @@ -83,6 +87,16 @@ std::unique_ptr Clock::WatchFaceDigitalScreen() { motionController); } +std::unique_ptr Clock::WatchFaceBinaryScreen() { + return std::make_unique(dateTimeController, + batteryController, + bleController, + notificationManager, + settingsController, + heartRateController, + motionController); +} + std::unique_ptr Clock::WatchFaceAnalogScreen() { return std::make_unique(dateTimeController, batteryController, diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h index f3591f43..ba4e4e67 100644 --- a/src/displayapp/screens/Clock.h +++ b/src/displayapp/screens/Clock.h @@ -50,6 +50,7 @@ namespace Pinetime { std::unique_ptr screen; std::unique_ptr WatchFaceDigitalScreen(); std::unique_ptr WatchFaceAnalogScreen(); + std::unique_ptr WatchFaceBinaryScreen(); std::unique_ptr WatchFacePineTimeStyleScreen(); std::unique_ptr WatchFaceTerminalScreen(); std::unique_ptr WatchFaceInfineatScreen(); diff --git a/src/displayapp/screens/WatchFaceBinary.cpp b/src/displayapp/screens/WatchFaceBinary.cpp new file mode 100644 index 00000000..638fc552 --- /dev/null +++ b/src/displayapp/screens/WatchFaceBinary.cpp @@ -0,0 +1,245 @@ +#include "displayapp/screens/WatchFaceBinary.h" + +#include +#include +#include "displayapp/screens/NotificationIcon.h" +#include "displayapp/screens/Symbols.h" +#include "components/battery/BatteryController.h" +#include "components/ble/BleController.h" +#include "components/ble/NotificationManager.h" +#include "components/heartrate/HeartRateController.h" +#include "components/motion/MotionController.h" +#include "components/settings/Settings.h" + + +#define LV_COLOR_MATRIX_GREEN LV_COLOR_MAKE(0x00, 0xC0, 0x16) +#define BINARY_ON_COLOR LV_COLOR_RED +#define BINARY_OFF_COLOR LV_COLOR_GRAY + +const uint8_t pointSize = 32; +const uint8_t widthSpacer = 8; +const uint8_t offsetX = ( LV_HOR_RES - ( ( pointSize * 6 ) + 2 * widthSpacer ) ) / 5; +const uint8_t offsetY = pointSize * 1.25; +const int16_t hourY = 32; +const int16_t minuteY = hourY + offsetY; +const int16_t secondY = minuteY + offsetY; +const uint8_t tflHeight = (pointSize - 3) / 2; +const uint8_t tflOffsetX = 4; +const int8_t tflOffsetY = -4; +bool is12HourModeSet; + +using namespace Pinetime::Applications::Screens; + +WatchFaceBinary::WatchFaceBinary(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController) + : currentDateTime {{}}, + dateTimeController {dateTimeController}, + notificationManager {notificationManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController}, + statusIcons(batteryController, bleController) { + + statusIcons.Create(); + + 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, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + label_date = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); + lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + + heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + + heartbeatValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_label_set_text_static(heartbeatValue, ""); + lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); + + for ( uint8_t i = 0; i < 6; i++ ) + { + // Hours + if ( 5 > i ) + { + hour_points[i] = lv_obj_create(lv_scr_act(), nullptr); + + lv_obj_set_style_local_bg_color(hour_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_radius(hour_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(hour_points[i], pointSize, pointSize); + lv_obj_set_pos(hour_points[i], widthSpacer + (pointSize + offsetX) * i, hourY); + } + // Minutes + minute_points[i] = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(minute_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_radius(minute_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(minute_points[i], pointSize, pointSize); + lv_obj_set_pos(minute_points[i], widthSpacer + (pointSize + offsetX) * i, minuteY); + // Seconds + second_points[i] = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(second_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_radius(second_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(second_points[i], pointSize, pointSize); + lv_obj_set_pos(second_points[i], widthSpacer + (pointSize + offsetX) * i, secondY); + } + + label_am = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(label_am, "AM"); + lv_obj_set_pos(label_am, widthSpacer + tflOffsetX + (pointSize + offsetX) * 5, hourY + tflOffsetY); + lv_obj_set_style_local_text_color(label_am, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_size(label_am, pointSize, tflHeight); + + label_pm = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(label_pm, "PM"); + lv_obj_set_pos(label_pm, widthSpacer + tflOffsetX + (pointSize + offsetX) * 5, hourY + tflOffsetY + tflHeight + 1); + lv_obj_set_style_local_text_color(label_pm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_size(label_pm, pointSize, tflHeight); + + is12HourModeSet = ( settingsController.GetClockType() == Controllers::Settings::ClockType::H12 ); + lv_obj_set_hidden(hour_points[4], is12HourModeSet); + lv_obj_set_hidden(label_am, !is12HourModeSet); + lv_obj_set_hidden(label_pm, !is12HourModeSet); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceBinary::~WatchFaceBinary() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceBinary::Refresh() { + statusIcons.Update(); + + notificationState = notificationManager.AreNewNotificationsAvailable(); + if (notificationState.IsUpdated()) { + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + } + + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + + if (currentDateTime.IsUpdated()) { + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + uint8_t seconds = dateTimeController.Seconds(); + + if ( settingsController.GetClockType() == Controllers::Settings::ClockType::H12 ) + { + if ( !is12HourModeSet ) + { + is12HourModeSet = true; + } + + if ( ( 12 <= hour ) && ( 24 > hour ) ) + { + if ( 12 != hour ) + { + hour -= 12; + } + lv_obj_set_style_local_text_color(label_am, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_text_color(label_pm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + } + else + { + if ( 0 == hour ) + { + hour = 12; + } + lv_obj_set_style_local_text_color(label_am, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + lv_obj_set_style_local_text_color(label_pm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + } + hour <<= 1; + } + else if ( is12HourModeSet ) + { + is12HourModeSet = false; + } + lv_obj_set_hidden(hour_points[4], is12HourModeSet); + lv_obj_set_hidden(label_am, !is12HourModeSet); + lv_obj_set_hidden(label_pm, !is12HourModeSet); + + for ( uint8_t i = 0; i < 6; i++ ) + { + // Hours + if ( 5 > i ) + { + switch ( hour >> i & 0b1 ) + { + case 1: + lv_obj_set_style_local_bg_color(hour_points[4 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + break; + default: + lv_obj_set_style_local_bg_color(hour_points[4 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + break; + } + } + // Minutes + switch ( minute >> i & 0b1 ) + { + case 1: + lv_obj_set_style_local_bg_color(minute_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + break; + default: + lv_obj_set_style_local_bg_color(minute_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + break; + } + // Seconds + switch ( seconds >> i & 0b1 ) + { + case 1: + lv_obj_set_style_local_bg_color(second_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + break; + default: + lv_obj_set_style_local_bg_color(second_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + break; + } + } + + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + if (currentDate.IsUpdated()) { + uint16_t year = dateTimeController.Year(); + uint8_t day = dateTimeController.Day(); + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { + lv_label_set_text_fmt(label_date, + "%s %d %s %d", + dateTimeController.DayOfWeekShortToString(), + day, + dateTimeController.MonthShortToString(), + year); + } else { + lv_label_set_text_fmt(label_date, + "%s %s %d %d", + dateTimeController.DayOfWeekShortToString(), + dateTimeController.MonthShortToString(), + day, + year); + } + lv_obj_realign(label_date); + } + } + + heartbeat = heartRateController.HeartRate(); + heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; + if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { + if (heartbeatRunning.Get()) { + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get()); + } else { + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B)); + lv_label_set_text_static(heartbeatValue, ""); + } + + lv_obj_realign(heartbeatIcon); + lv_obj_realign(heartbeatValue); + } +} diff --git a/src/displayapp/screens/WatchFaceBinary.h b/src/displayapp/screens/WatchFaceBinary.h new file mode 100644 index 00000000..ddd408ba --- /dev/null +++ b/src/displayapp/screens/WatchFaceBinary.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include "components/ble/BleController.h" +#include "displayapp/widgets/StatusIcons.h" +#include "utility/DirtyValue.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + + namespace Applications { + namespace Screens { + + class WatchFaceBinary : public Screen { + public: + WatchFaceBinary(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController); + ~WatchFaceBinary() override; + + void Refresh() override; + + private: + Utility::DirtyValue batteryPercentRemaining {}; + Utility::DirtyValue powerPresent {}; + Utility::DirtyValue bleState {}; + Utility::DirtyValue bleRadioEnabled {}; + Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue heartbeat {}; + Utility::DirtyValue heartbeatRunning {}; + Utility::DirtyValue notificationState {}; + using days = std::chrono::duration>; // TODO: days is standard in c++20 + Utility::DirtyValue> currentDate; + + lv_obj_t* label_date; + lv_obj_t* label_am; + lv_obj_t* label_pm; + lv_obj_t* heartbeatIcon; + lv_obj_t* heartbeatValue; + lv_obj_t* notificationIcon; + + lv_obj_t* hour_points[5]; + lv_obj_t* minute_points[6]; + lv_obj_t* second_points[6]; + + Controllers::DateTime& dateTimeController; + Controllers::NotificationManager& notificationManager; + Controllers::Settings& settingsController; + Controllers::HeartRateController& heartRateController; + Controllers::MotionController& motionController; + + lv_task_t* taskRefresh; + Widgets::StatusIcons statusIcons; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 45a50e3d..d1264b58 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -43,11 +43,11 @@ namespace Pinetime { std::array watchfaces { {{"Digital face", true}, {"Analog face", true}, + {"Binary", true}, {"PineTimeStyle", true}, {"Terminal", true}, {"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)}, {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)}, - {"", false}, {"", false}}}; ScreenList screens; }; From e7bc82e772c5d59e6d16cfbc73bc724e2c2a20c5 Mon Sep 17 00:00:00 2001 From: Adrian Date: Sat, 11 Nov 2023 23:57:50 +0100 Subject: [PATCH 2/4] WatchFaceBinary: Made second optional for building InfiniTime Added define to enable/disable seconds for the binary clock in a build --- src/CMakeLists.txt | 1 + src/displayapp/screens/WatchFaceBinary.cpp | 306 ++++++++++++--------- src/displayapp/screens/WatchFaceBinary.h | 39 ++- 3 files changed, 200 insertions(+), 146 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e8e9686..3ccc1183 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -429,6 +429,7 @@ list(APPEND SOURCE_FILES ## Watch faces displayapp/screens/WatchFaceAnalog.cpp displayapp/screens/WatchFaceDigital.cpp + displayapp/screens/WatchFaceBinary.cpp displayapp/screens/WatchFaceInfineat.cpp displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFacePineTimeStyle.cpp diff --git a/src/displayapp/screens/WatchFaceBinary.cpp b/src/displayapp/screens/WatchFaceBinary.cpp index 638fc552..a68a4f73 100644 --- a/src/displayapp/screens/WatchFaceBinary.cpp +++ b/src/displayapp/screens/WatchFaceBinary.cpp @@ -11,32 +11,15 @@ #include "components/motion/MotionController.h" #include "components/settings/Settings.h" - -#define LV_COLOR_MATRIX_GREEN LV_COLOR_MAKE(0x00, 0xC0, 0x16) -#define BINARY_ON_COLOR LV_COLOR_RED -#define BINARY_OFF_COLOR LV_COLOR_GRAY - -const uint8_t pointSize = 32; -const uint8_t widthSpacer = 8; -const uint8_t offsetX = ( LV_HOR_RES - ( ( pointSize * 6 ) + 2 * widthSpacer ) ) / 5; -const uint8_t offsetY = pointSize * 1.25; -const int16_t hourY = 32; -const int16_t minuteY = hourY + offsetY; -const int16_t secondY = minuteY + offsetY; -const uint8_t tflHeight = (pointSize - 3) / 2; -const uint8_t tflOffsetX = 4; -const int8_t tflOffsetY = -4; -bool is12HourModeSet; - using namespace Pinetime::Applications::Screens; WatchFaceBinary::WatchFaceBinary(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController) + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController) : currentDateTime {{}}, dateTimeController {dateTimeController}, notificationManager {notificationManager}, @@ -52,9 +35,79 @@ WatchFaceBinary::WatchFaceBinary(Controllers::DateTime& dateTimeController, lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - label_date = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); - lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lableDate = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(lableDate, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); + lv_obj_set_style_local_text_color(lableDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + + constexpr lv_coord_t pointSize = 32; + constexpr lv_coord_t widthSpacer = 8; + auto offsetX = (lv_coord_t) ((LV_HOR_RES - ((pointSize * 6) + 2 * widthSpacer)) / 5); + +#if BINARY_SECONDS_ENABLED + constexpr lv_coord_t hourY = 32; + constexpr lv_coord_t offsetY = pointSize * 1.25; +#else + constexpr lv_coord_t hourY = 48; + constexpr lv_coord_t offsetY = pointSize * 1.5; +#endif + + constexpr lv_coord_t minuteY = hourY + offsetY; + +#if BINARY_SECONDS_ENABLED + constexpr lv_coord_t secondY = minuteY + offsetY; +#endif + + constexpr lv_coord_t tflOffsetX = 4; + constexpr lv_coord_t tflHeight = (pointSize - tflOffsetX) / 2; + constexpr lv_coord_t tflOffsetY = -4; + + auto labelAMpmX = (lv_coord_t) (widthSpacer + tflOffsetX + (pointSize + offsetX) * 5); + constexpr lv_coord_t labelAMy = hourY + tflOffsetY; + + for (uint8_t i = 0; i < 6; i++) { + // Hours + if (5 > i) { + hourPoints[i] = lv_obj_create(lv_scr_act(), nullptr); + + lv_obj_set_style_local_bg_color(hourPoints[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_radius(hourPoints[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(hourPoints[i], pointSize, pointSize); + lv_obj_set_pos(hourPoints[i], (lv_coord_t) (widthSpacer + (pointSize + offsetX) * i), hourY); + } + // Minutes + minutePoints[i] = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(minutePoints[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_radius(minutePoints[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(minutePoints[i], pointSize, pointSize); + lv_obj_set_pos(minutePoints[i], (lv_coord_t) (widthSpacer + (pointSize + offsetX) * i), minuteY); + +// Seconds +#if BINARY_SECONDS_ENABLED + secondPoints[i] = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(secondPoints[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_radius(secondPoints[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(secondPoints[i], pointSize, pointSize); + lv_obj_set_pos(secondPoints[i], (lv_coord_t) (widthSpacer + (pointSize + offsetX) * i), secondY); +#endif + } + + labelAM = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(labelAM, "AM"); + lv_obj_set_pos(labelAM, labelAMpmX, labelAMy); + lv_obj_set_style_local_text_color(labelAM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_size(labelAM, pointSize, tflHeight); + + labelPM = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(labelPM, "PM"); + lv_obj_set_pos(labelPM, labelAMpmX, labelAMy + tflHeight + 1); + lv_obj_set_style_local_text_color(labelPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_size(labelPM, pointSize, tflHeight); + + lastClockType = settingsController.GetClockType(); + is12HourModeSet = (settingsController.GetClockType() == Controllers::Settings::ClockType::H12); + lv_obj_set_hidden(hourPoints[4], is12HourModeSet); + lv_obj_set_hidden(labelAM, !is12HourModeSet); + lv_obj_set_hidden(labelPM, !is12HourModeSet); heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); @@ -66,48 +119,15 @@ WatchFaceBinary::WatchFaceBinary(Controllers::DateTime& dateTimeController, lv_label_set_text_static(heartbeatValue, ""); lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); - for ( uint8_t i = 0; i < 6; i++ ) - { - // Hours - if ( 5 > i ) - { - hour_points[i] = lv_obj_create(lv_scr_act(), nullptr); + stepValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); + lv_label_set_text_static(stepValue, "0"); + lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - lv_obj_set_style_local_bg_color(hour_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - lv_obj_set_style_local_radius(hour_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_size(hour_points[i], pointSize, pointSize); - lv_obj_set_pos(hour_points[i], widthSpacer + (pointSize + offsetX) * i, hourY); - } - // Minutes - minute_points[i] = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(minute_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - lv_obj_set_style_local_radius(minute_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_size(minute_points[i], pointSize, pointSize); - lv_obj_set_pos(minute_points[i], widthSpacer + (pointSize + offsetX) * i, minuteY); - // Seconds - second_points[i] = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(second_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - lv_obj_set_style_local_radius(second_points[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_size(second_points[i], pointSize, pointSize); - lv_obj_set_pos(second_points[i], widthSpacer + (pointSize + offsetX) * i, secondY); - } - - label_am = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(label_am, "AM"); - lv_obj_set_pos(label_am, widthSpacer + tflOffsetX + (pointSize + offsetX) * 5, hourY + tflOffsetY); - lv_obj_set_style_local_text_color(label_am, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - lv_obj_set_size(label_am, pointSize, tflHeight); - - label_pm = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(label_pm, "PM"); - lv_obj_set_pos(label_pm, widthSpacer + tflOffsetX + (pointSize + offsetX) * 5, hourY + tflOffsetY + tflHeight + 1); - lv_obj_set_style_local_text_color(label_pm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - lv_obj_set_size(label_pm, pointSize, tflHeight); - - is12HourModeSet = ( settingsController.GetClockType() == Controllers::Settings::ClockType::H12 ); - lv_obj_set_hidden(hour_points[4], is12HourModeSet); - lv_obj_set_hidden(label_am, !is12HourModeSet); - lv_obj_set_hidden(label_pm, !is12HourModeSet); + stepIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); + lv_label_set_text_static(stepIcon, Symbols::shoe); + lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); Refresh(); @@ -129,102 +149,113 @@ void WatchFaceBinary::Refresh() { currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); if (currentDateTime.IsUpdated()) { - uint8_t hour = dateTimeController.Hours(); - uint8_t minute = dateTimeController.Minutes(); - uint8_t seconds = dateTimeController.Seconds(); + uint8_t hours = dateTimeController.Hours(); + const uint8_t minutes = dateTimeController.Minutes(); +#if BINARY_SECONDS_ENABLED + const uint8_t seconds = dateTimeController.Seconds(); +#endif - if ( settingsController.GetClockType() == Controllers::Settings::ClockType::H12 ) - { - if ( !is12HourModeSet ) - { + const bool shouldUpdateHours = (displayedHours != hours); + const bool shouldUpdateMinutes = (displayedMinutes != minutes); + const bool clockTypeChanged = (settingsController.GetClockType() != lastClockType); + + if ((settingsController.GetClockType() == Controllers::Settings::ClockType::H12) && (shouldUpdateHours || clockTypeChanged)) { + lastClockType = Controllers::Settings::ClockType::H12; + + if (!is12HourModeSet) { is12HourModeSet = true; } - if ( ( 12 <= hour ) && ( 24 > hour ) ) - { - if ( 12 != hour ) - { - hour -= 12; + if ((12 <= hours) && (24 > hours)) { + if (12 != hours) { + hours -= 12; } - lv_obj_set_style_local_text_color(label_am, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - lv_obj_set_style_local_text_color(label_pm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); - } - else - { - if ( 0 == hour ) - { - hour = 12; + lv_obj_set_style_local_text_color(labelAM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_text_color(labelPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + } else { + if (0 == hours) { + hours = 12; } - lv_obj_set_style_local_text_color(label_am, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); - lv_obj_set_style_local_text_color(label_pm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + lv_obj_set_style_local_text_color(labelAM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + lv_obj_set_style_local_text_color(labelPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); } - hour <<= 1; - } - else if ( is12HourModeSet ) - { + hours <<= 1; + } else if (is12HourModeSet) { is12HourModeSet = false; } - lv_obj_set_hidden(hour_points[4], is12HourModeSet); - lv_obj_set_hidden(label_am, !is12HourModeSet); - lv_obj_set_hidden(label_pm, !is12HourModeSet); - for ( uint8_t i = 0; i < 6; i++ ) - { - // Hours - if ( 5 > i ) - { - switch ( hour >> i & 0b1 ) - { - case 1: - lv_obj_set_style_local_bg_color(hour_points[4 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); - break; - default: - lv_obj_set_style_local_bg_color(hour_points[4 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - break; + if (shouldUpdateHours) { + displayedHours = hours; + } + + if (shouldUpdateMinutes) { + displayedMinutes = minutes; + } + + if (clockTypeChanged) { + lv_obj_set_hidden(hourPoints[4], is12HourModeSet); + lv_obj_set_hidden(labelAM, !is12HourModeSet); + lv_obj_set_hidden(labelPM, !is12HourModeSet); + } + + if (BINARY_SECONDS_ENABLED || shouldUpdateHours || shouldUpdateMinutes) { + for (uint8_t i = 0; i < 6; i++) { + // Hours + if (shouldUpdateHours && (5 > i)) { + switch (hours >> i & 0b1) { + case 1: + lv_obj_set_style_local_bg_color(hourPoints[4 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + break; + default: + lv_obj_set_style_local_bg_color(hourPoints[4 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + break; + } } - } - // Minutes - switch ( minute >> i & 0b1 ) - { - case 1: - lv_obj_set_style_local_bg_color(minute_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); - break; - default: - lv_obj_set_style_local_bg_color(minute_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - break; - } - // Seconds - switch ( seconds >> i & 0b1 ) - { - case 1: - lv_obj_set_style_local_bg_color(second_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); - break; - default: - lv_obj_set_style_local_bg_color(second_points[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); - break; + // Minutes + if (shouldUpdateMinutes) { + switch (minutes >> i & 0b1) { + case 1: + lv_obj_set_style_local_bg_color(minutePoints[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + break; + default: + lv_obj_set_style_local_bg_color(minutePoints[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + break; + } + } +// Seconds +#if BINARY_SECONDS_ENABLED + switch (seconds >> i & 0b1) { + case 1: + lv_obj_set_style_local_bg_color(secondPoints[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_ON_COLOR); + break; + default: + lv_obj_set_style_local_bg_color(secondPoints[5 - i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, BINARY_OFF_COLOR); + break; + } +#endif } } currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { - uint16_t year = dateTimeController.Year(); - uint8_t day = dateTimeController.Day(); + const uint16_t year = dateTimeController.Year(); + const uint8_t day = dateTimeController.Day(); if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - lv_label_set_text_fmt(label_date, + lv_label_set_text_fmt(lableDate, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year); } else { - lv_label_set_text_fmt(label_date, + lv_label_set_text_fmt(lableDate, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year); } - lv_obj_realign(label_date); + lv_obj_realign(lableDate); } } @@ -242,4 +273,11 @@ void WatchFaceBinary::Refresh() { lv_obj_realign(heartbeatIcon); lv_obj_realign(heartbeatValue); } + + stepCount = motionController.NbSteps(); + if (stepCount.IsUpdated()) { + lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get()); + lv_obj_realign(stepValue); + lv_obj_realign(stepIcon); + } } diff --git a/src/displayapp/screens/WatchFaceBinary.h b/src/displayapp/screens/WatchFaceBinary.h index ddd408ba..a872815d 100644 --- a/src/displayapp/screens/WatchFaceBinary.h +++ b/src/displayapp/screens/WatchFaceBinary.h @@ -10,6 +10,11 @@ #include "displayapp/widgets/StatusIcons.h" #include "utility/DirtyValue.h" +// #define LV_COLOR_MATRIX_GREEN LV_COLOR_MAKE(0x00, 0xC0, 0x16) +#define BINARY_ON_COLOR LV_COLOR_RED +#define BINARY_OFF_COLOR LV_COLOR_GRAY +#define BINARY_SECONDS_ENABLED false + namespace Pinetime { namespace Controllers { class Settings; @@ -26,38 +31,48 @@ namespace Pinetime { class WatchFaceBinary : public Screen { public: WatchFaceBinary(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController); + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController); ~WatchFaceBinary() override; void Refresh() override; private: + uint8_t displayedHours = -1; + uint8_t displayedMinutes = -1; + bool is12HourModeSet = false; + Controllers::Settings::ClockType lastClockType; + Utility::DirtyValue batteryPercentRemaining {}; Utility::DirtyValue powerPresent {}; Utility::DirtyValue bleState {}; Utility::DirtyValue bleRadioEnabled {}; Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue stepCount {}; Utility::DirtyValue heartbeat {}; Utility::DirtyValue heartbeatRunning {}; Utility::DirtyValue notificationState {}; using days = std::chrono::duration>; // TODO: days is standard in c++20 Utility::DirtyValue> currentDate; - lv_obj_t* label_date; - lv_obj_t* label_am; - lv_obj_t* label_pm; lv_obj_t* heartbeatIcon; lv_obj_t* heartbeatValue; + lv_obj_t* stepIcon; + lv_obj_t* stepValue; lv_obj_t* notificationIcon; - lv_obj_t* hour_points[5]; - lv_obj_t* minute_points[6]; - lv_obj_t* second_points[6]; + lv_obj_t* lableDate; + lv_obj_t* labelAM; + lv_obj_t* labelPM; + lv_obj_t* hourPoints[5]; + lv_obj_t* minutePoints[6]; +#if BINARY_SECONDS_ENABLED + lv_obj_t* secondPoints[6]; +#endif Controllers::DateTime& dateTimeController; Controllers::NotificationManager& notificationManager; From f9cb05d7064793fd58c27b2bd281c14fdd471c94 Mon Sep 17 00:00:00 2001 From: locker98 Date: Sat, 11 May 2024 19:27:07 -0400 Subject: [PATCH 3/4] Added Documentation on flashing pinetime with esp32 --- doc/Flashing Your Watch with an ESP32.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 doc/Flashing Your Watch with an ESP32.md diff --git a/doc/Flashing Your Watch with an ESP32.md b/doc/Flashing Your Watch with an ESP32.md new file mode 100644 index 00000000..5aa9b07b --- /dev/null +++ b/doc/Flashing Your Watch with an ESP32.md @@ -0,0 +1,12 @@ +# Flashing your watch with an ESP + +Here is a link about how to access and wire an SWD to the pinetime. +- https://pine64.org/documentation/PineTime/Further_information/Devkit_wiring + + +Here is a link that tells you how to setup the esp32 as a SWD. +- https://hackaday.com/2021/07/01/esp3F2-turned-handy-swd-flasher-for-nrf52-chips/ +- When setting up WiFi got to http://192.168.4.1/0wifi to set the WiFi password and not crash the esp. If you go to the default http://192.168.4.1/wifi then the esp will often crash due to a watchdog timeout. + +Here is the link to the information on what files to flash to your pinetime. +- https://gitea.locker98.com/josh/InfiniTime/src/branch/v14/doc/SWD.md \ No newline at end of file From 4e6259541f7e70bd0b78f4ef783ad3a4cf3c46b0 Mon Sep 17 00:00:00 2001 From: locker98 Date: Mon, 13 May 2024 14:29:19 -0400 Subject: [PATCH 4/4] added binary needs work --- src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 8cc34943..4b978b5a 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -53,6 +53,7 @@ namespace Pinetime { enum class WatchFace : uint8_t { Digital, Analog, + Binary, PineTimeStyle, Terminal, Infineat, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 85281926..defbc8a6 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -26,6 +26,7 @@ if(DEFINED ENABLE_WATCHFACES) else() set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Binary") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat")