From 947ece0bc9ad90dd4c1fcd5875594a4a48eddd56 Mon Sep 17 00:00:00 2001 From: Mark Russell Date: Wed, 10 Nov 2021 20:11:09 -0500 Subject: [PATCH 01/78] Status bar displays time in 12 or 24 hour format based on settings --- .../datetime/DateTimeController.cpp | 23 +++++++++++++++++++ src/components/datetime/DateTimeController.h | 5 ++++ src/components/settings/Settings.h | 1 - src/displayapp/screens/Tile.cpp | 4 ++-- .../screens/settings/QuickSettings.cpp | 4 ++-- src/main.cpp | 10 ++++---- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index e9c5d870db..49b3e75e0f 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -11,6 +11,9 @@ namespace { char const* MonthsStringLow[] = {"--", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; } +DateTime::DateTime(Controllers::Settings& settingsController) : settingsController {settingsController} { +} + void DateTime::SetCurrentTime(std::chrono::time_point t) { this->currentDateTime = t; UpdateTime(previousSystickCounter); // Update internal state without updating the time @@ -101,3 +104,23 @@ void DateTime::Register(Pinetime::System::SystemTask* systemTask) { this->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]; + if (settingsController.GetClockType() == ClockType::H12) { + uint8_t hour12; + const char* amPmStr; + if (hour < 12) { + hour12 = (hour == 0) ? 12 : hour; + amPmStr = "AM"; + } else { + hour12 = (hour == 12) ? 12 : hour - 12; + amPmStr = "PM"; + } + sprintf(buff, "%i:%02i %s", hour12, minute, amPmStr); + } else { + sprintf(buff, "%02i:%02i", hour, minute); + } + return std::string(buff); +} diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 77ed68e8a0..19e8fc4630 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -2,6 +2,8 @@ #include #include +#include +#include "components/settings/Settings.h" namespace Pinetime { namespace System { @@ -10,6 +12,7 @@ namespace Pinetime { namespace Controllers { class DateTime { public: + DateTime(Controllers::Settings& settingsController); enum class Days : uint8_t { Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; enum class Months : uint8_t { Unknown, @@ -71,6 +74,7 @@ namespace Pinetime { void Register(System::SystemTask* systemTask); void SetCurrentTime(std::chrono::time_point t); + std::string FormattedTime(); private: uint16_t year = 0; @@ -87,6 +91,7 @@ namespace Pinetime { bool isMidnightAlreadyNotified = false; System::SystemTask* systemTask = nullptr; + Controllers::Settings& settingsController; }; } } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 871ff3b6cf..d818cbe3c7 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -1,7 +1,6 @@ #pragma once #include #include -#include "components/datetime/DateTimeController.h" #include "components/brightness/BrightnessController.h" #include "components/fs/FS.h" #include "drivers/Cst816s.h" diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index 1d4f0d0ef7..761059107a 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -33,7 +33,7 @@ Tile::Tile(uint8_t screenID, // Time label_time = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_time, "%02i:%02i", dateTimeController.Hours(), dateTimeController.Minutes()); + lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER); lv_obj_align(label_time, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); @@ -119,7 +119,7 @@ Tile::~Tile() { } void Tile::UpdateScreen() { - lv_label_set_text_fmt(label_time, "%02i:%02i", dateTimeController.Hours(), dateTimeController.Minutes()); + lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryController.PercentRemaining())); } diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index dd62607212..a6ed144eab 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -35,7 +35,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, // Time label_time = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_time, "%02i:%02i", dateTimeController.Hours(), dateTimeController.Minutes()); + lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER); lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); @@ -123,7 +123,7 @@ QuickSettings::~QuickSettings() { } void QuickSettings::UpdateScreen() { - lv_label_set_text_fmt(label_time, "%02i:%02i", dateTimeController.Hours(), dateTimeController.Minutes()); + lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryController.PercentRemaining())); } diff --git a/src/main.cpp b/src/main.cpp index 53f78ce8a1..81d297f5ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,7 +101,11 @@ Pinetime::Controllers::Ble bleController; Pinetime::Controllers::HeartRateController heartRateController; Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController); -Pinetime::Controllers::DateTime dateTimeController; +Pinetime::Controllers::FS fs {spiNorFlash}; +Pinetime::Controllers::Settings settingsController {fs}; +Pinetime::Controllers::MotorController motorController {}; + +Pinetime::Controllers::DateTime dateTimeController {settingsController}; Pinetime::Drivers::Watchdog watchdog; Pinetime::Drivers::WatchdogView watchdogView(watchdog); Pinetime::Controllers::NotificationManager notificationManager; @@ -111,10 +115,6 @@ Pinetime::Controllers::AlarmController alarmController {dateTimeController}; Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl); Pinetime::Controllers::ButtonHandler buttonHandler; -Pinetime::Controllers::FS fs {spiNorFlash}; -Pinetime::Controllers::Settings settingsController {fs}; -Pinetime::Controllers::MotorController motorController {}; - Pinetime::Applications::DisplayApp displayApp(lcd, lvgl, touchPanel, From 4cc95091ab07f0b90c078f087f3826e845443873 Mon Sep 17 00:00:00 2001 From: Yehoshua Pesach Wallach Date: Mon, 13 Dec 2021 12:39:34 +0200 Subject: [PATCH 02/78] order ReadHrs, ReadAls bitwise according to bit ordering --- src/drivers/Hrs3300.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/Hrs3300.cpp b/src/drivers/Hrs3300.cpp index c14fe7aa7d..45458adc4f 100644 --- a/src/drivers/Hrs3300.cpp +++ b/src/drivers/Hrs3300.cpp @@ -58,14 +58,14 @@ uint16_t Hrs3300::ReadHrs() { auto m = ReadRegister(static_cast(Registers::C0DataM)); auto h = ReadRegister(static_cast(Registers::C0DataH)); auto l = ReadRegister(static_cast(Registers::C0dataL)); - return (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f) | ((l & 0x30) << 12); + return ((l & 0x30) << 12) | (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f); } uint16_t Hrs3300::ReadAls() { auto m = ReadRegister(static_cast(Registers::C1dataM)); auto h = ReadRegister(static_cast(Registers::C1dataH)); auto l = ReadRegister(static_cast(Registers::C1dataL)); - return (m << 3) | ((h & 0x3f) << 11) | (l & 0x07); + return ((h & 0x3f) << 11) | (m << 3) | (l & 0x07); } void Hrs3300::SetGain(uint8_t gain) { From 464b689a03bca06099fba316b4c6c66c619d5521 Mon Sep 17 00:00:00 2001 From: Yehoshua Pesach Wallach Date: Mon, 13 Dec 2021 12:47:52 +0200 Subject: [PATCH 03/78] changed ReadHrs and ReadAls to uint32, and did static_cast instead of hidden cast when using it --- src/drivers/Hrs3300.cpp | 4 ++-- src/drivers/Hrs3300.h | 4 ++-- src/heartratetask/HeartRateTask.cpp | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/drivers/Hrs3300.cpp b/src/drivers/Hrs3300.cpp index 45458adc4f..cfc476cbea 100644 --- a/src/drivers/Hrs3300.cpp +++ b/src/drivers/Hrs3300.cpp @@ -54,14 +54,14 @@ void Hrs3300::Disable() { WriteRegister(static_cast(Registers::Enable), value); } -uint16_t Hrs3300::ReadHrs() { +uint32_t Hrs3300::ReadHrs() { auto m = ReadRegister(static_cast(Registers::C0DataM)); auto h = ReadRegister(static_cast(Registers::C0DataH)); auto l = ReadRegister(static_cast(Registers::C0dataL)); return ((l & 0x30) << 12) | (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f); } -uint16_t Hrs3300::ReadAls() { +uint32_t Hrs3300::ReadAls() { auto m = ReadRegister(static_cast(Registers::C1dataM)); auto h = ReadRegister(static_cast(Registers::C1dataH)); auto l = ReadRegister(static_cast(Registers::C1dataL)); diff --git a/src/drivers/Hrs3300.h b/src/drivers/Hrs3300.h index 01310c6217..8bbdc69a40 100644 --- a/src/drivers/Hrs3300.h +++ b/src/drivers/Hrs3300.h @@ -30,8 +30,8 @@ namespace Pinetime { void Init(); void Enable(); void Disable(); - uint16_t ReadHrs(); - uint16_t ReadAls(); + uint32_t ReadHrs(); + uint32_t ReadAls(); void SetGain(uint8_t gain); void SetDrive(uint8_t drive); diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 213ab4a7e3..2f689b9b9f 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -65,8 +65,7 @@ void HeartRateTask::Work() { } if (measurementStarted) { - auto hrs = heartRateSensor.ReadHrs(); - ppg.Preprocess(hrs); + ppg.Preprocess(static_cast(heartRateSensor.ReadHrs())); auto bpm = ppg.HeartRate(); if (lastBpm == 0 && bpm == 0) From 319030d9e16e833cf8bff569a9ecfa452165ea27 Mon Sep 17 00:00:00 2001 From: "James A. Jerkins" Date: Thu, 23 Dec 2021 20:30:14 -0600 Subject: [PATCH 04/78] Add airplane mode feature Implements 'Airplane mode' feature to disable and enable bluetooth/ble Adds airplaneMode as a non-persisted setting Adds a setting menu for switching airplane mode on and off Displays an airplane symbol on the Digital watch face and the PineTimeStyle watch face when airplane mode is enabled Always enables bluetooth/ble on boot (disable airplane mode) Alphabetizes the settings menu options Style cleanups Closes #632 --- src/CMakeLists.txt | 1 + src/components/ble/BleController.cpp | 8 +- src/components/ble/BleController.h | 9 +- src/components/ble/NimbleController.cpp | 44 ++++++--- src/components/ble/NimbleController.h | 28 +++--- src/components/settings/Settings.h | 39 +++++++- src/displayapp/Apps.h | 3 +- src/displayapp/DisplayApp.cpp | 8 ++ src/displayapp/Messages.h | 3 +- src/displayapp/fonts/README.md | 2 +- src/displayapp/fonts/jetbrains_mono_bold_20.c | 74 ++++++++------- src/displayapp/screens/BleIcon.cpp | 10 ++- src/displayapp/screens/BleIcon.h | 6 +- src/displayapp/screens/PineTimeStyle.cpp | 6 +- src/displayapp/screens/PineTimeStyle.h | 7 +- src/displayapp/screens/Symbols.h | 1 + src/displayapp/screens/WatchFaceDigital.cpp | 2 +- src/displayapp/screens/WatchFaceDigital.h | 7 +- .../screens/settings/SettingAirplaneMode.cpp | 89 +++++++++++++++++++ .../screens/settings/SettingAirplaneMode.h | 30 +++++++ src/displayapp/screens/settings/Settings.cpp | 22 ++--- src/systemtask/Messages.h | 1 + src/systemtask/SystemTask.cpp | 6 +- 23 files changed, 307 insertions(+), 99 deletions(-) create mode 100644 src/displayapp/screens/settings/SettingAirplaneMode.cpp create mode 100644 src/displayapp/screens/settings/SettingAirplaneMode.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 809544c92f..ae8eece843 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -448,6 +448,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingPineTimeStyle.cpp displayapp/screens/settings/SettingSetDate.cpp displayapp/screens/settings/SettingSetTime.cpp + displayapp/screens/settings/SettingAirplaneMode.cpp ## Watch faces displayapp/icons/bg_clock.c diff --git a/src/components/ble/BleController.cpp b/src/components/ble/BleController.cpp index a80c97192e..0e1c5d7e5e 100644 --- a/src/components/ble/BleController.cpp +++ b/src/components/ble/BleController.cpp @@ -2,12 +2,12 @@ using namespace Pinetime::Controllers; -void Ble::Connect() { - isConnected = true; +void Ble::SetConnectState(Ble::ConnectStates newState) { + connectionState = newState; } -void Ble::Disconnect() { - isConnected = false; +Ble::ConnectStates Ble::GetConnectState() const { + return connectionState; } void Ble::StartFirmwareUpdate() { diff --git a/src/components/ble/BleController.h b/src/components/ble/BleController.h index 72b8766385..2714c0c3c7 100644 --- a/src/components/ble/BleController.h +++ b/src/components/ble/BleController.h @@ -10,13 +10,14 @@ namespace Pinetime { using BleAddress = std::array; enum class FirmwareUpdateStates { Idle, Running, Validated, Error }; enum class AddressTypes { Public, Random, RPA_Public, RPA_Random }; + enum class ConnectStates { Disconnected, Connected, Airplane }; Ble() = default; bool IsConnected() const { - return isConnected; + return (connectionState == ConnectStates::Connected); } - void Connect(); - void Disconnect(); + void SetConnectState(ConnectStates newState); + ConnectStates GetConnectState() const; void StartFirmwareUpdate(); void StopFirmwareUpdate(); @@ -56,7 +57,7 @@ namespace Pinetime { } private: - bool isConnected = false; + ConnectStates connectionState = ConnectStates::Disconnected; bool isFirmwareUpdating = false; uint32_t firmwareUpdateTotalBytes = 0; uint32_t firmwareUpdateCurrentBytes = 0; diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index d8510bd36c..d85ec5dcf2 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -23,14 +23,14 @@ using namespace Pinetime::Controllers; NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, - Pinetime::Controllers::Ble& bleController, + Ble& bleController, DateTime& dateTimeController, - Pinetime::Controllers::NotificationManager& notificationManager, - Controllers::Battery& batteryController, + NotificationManager& notificationManager, + Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::FS& fs) + HeartRateController& heartRateController, + MotionController& motionController, + FS& fs) : systemTask {systemTask}, bleController {bleController}, dateTimeController {dateTimeController}, @@ -184,7 +184,9 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { case BLE_GAP_EVENT_ADV_COMPLETE: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE"); NRF_LOG_INFO("reason=%d; status=%0X", event->adv_complete.reason, event->connect.status); - StartAdvertising(); + if (bleController.GetConnectState() == Ble::ConnectStates::Disconnected) { + StartAdvertising(); + } break; case BLE_GAP_EVENT_CONNECT: @@ -197,12 +199,12 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { currentTimeClient.Reset(); alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; - bleController.Disconnect(); + bleController.SetConnectState(Ble::ConnectStates::Disconnected); fastAdvCount = 0; StartAdvertising(); } else { connectionHandle = event->connect.conn_handle; - bleController.Connect(); + bleController.SetConnectState(Ble::ConnectStates::Connected); systemTask.PushMessage(Pinetime::System::Messages::BleConnected); // Service discovery is deferred via systemtask } @@ -220,9 +222,11 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { currentTimeClient.Reset(); alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; - bleController.Disconnect(); - fastAdvCount = 0; - StartAdvertising(); + if (bleController.GetConnectState() == Ble::ConnectStates::Connected) { + bleController.SetConnectState(Ble::ConnectStates::Disconnected); + fastAdvCount = 0; + StartAdvertising(); + } break; case BLE_GAP_EVENT_CONN_UPDATE: @@ -376,6 +380,22 @@ void NimbleController::NotifyBatteryLevel(uint8_t level) { } } +void NimbleController::SwitchAirplaneMode(bool enabled) { + if (enabled) { + if (bleController.IsConnected()) { + bleController.SetConnectState(Ble::ConnectStates::Airplane); + ble_gap_terminate(connectionHandle, BLE_ERR_REM_USER_CONN_TERM); + } else { + bleController.SetConnectState(Ble::ConnectStates::Airplane); + ble_gap_adv_stop(); + } + } else { + bleController.SetConnectState(Ble::ConnectStates::Disconnected); + fastAdvCount = 0; + StartAdvertising(); + } +} + void NimbleController::PersistBond(struct ble_gap_conn_desc& desc) { union ble_store_key key; union ble_store_value our_sec, peer_sec, peer_cccd_set[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)] = {0}; diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 2b300e630e..7219ba6b86 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -14,6 +14,7 @@ #include "components/ble/CurrentTimeService.h" #include "components/ble/DeviceInformationService.h" #include "components/ble/DfuService.h" +#include "components/ble/FSService.h" #include "components/ble/HeartRateService.h" #include "components/ble/ImmediateAlertService.h" #include "components/ble/MusicService.h" @@ -22,7 +23,6 @@ #include "components/ble/MotionService.h" #include "components/ble/weather/WeatherService.h" #include "components/fs/FS.h" -#include "components/ble/FSService.h" namespace Pinetime { namespace Drivers { @@ -42,18 +42,19 @@ namespace Pinetime { public: NimbleController(Pinetime::System::SystemTask& systemTask, - Pinetime::Controllers::Ble& bleController, + Ble& bleController, DateTime& dateTimeController, - Pinetime::Controllers::NotificationManager& notificationManager, - Controllers::Battery& batteryController, + NotificationManager& notificationManager, + Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Pinetime::Controllers::FS& fs); + HeartRateController& heartRateController, + MotionController& motionController, + FS& fs); void Init(); void StartAdvertising(); int OnGAPEvent(ble_gap_event* event); + /* these are not implemented yet int OnDiscoveryEvent(uint16_t i, const ble_gatt_error* pError, const ble_gatt_svc* pSvc); int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); @@ -62,6 +63,7 @@ namespace Pinetime { const ble_gatt_error* error, uint16_t characteristicValueHandle, const ble_gatt_dsc* descriptor); + */ void StartDiscovery(); @@ -83,7 +85,9 @@ namespace Pinetime { void RestartFastAdv() { fastAdvCount = 0; - } + }; + + void SwitchAirplaneMode(bool enabled); private: void PersistBond(struct ble_gap_conn_desc& desc); @@ -91,12 +95,12 @@ namespace Pinetime { static constexpr const char* deviceName = "InfiniTime"; Pinetime::System::SystemTask& systemTask; - Pinetime::Controllers::Ble& bleController; + Ble& bleController; DateTime& dateTimeController; - Pinetime::Controllers::NotificationManager& notificationManager; + NotificationManager& notificationManager; Pinetime::Drivers::SpiNorFlash& spiNorFlash; - Pinetime::Controllers::FS& fs; - Pinetime::Controllers::DfuService dfuService; + FS& fs; + DfuService dfuService; DeviceInformationService deviceInformationService; CurrentTimeClient currentTimeClient; diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 2d7973d8f0..a1529fecc5 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -17,7 +17,23 @@ namespace Pinetime { RaiseWrist = 2, }; enum class Colors : uint8_t { - White, Silver, Gray, Black, Red, Maroon, Yellow, Olive, Lime, Green, Cyan, Teal, Blue, Navy, Magenta, Purple, Orange + White, + Silver, + Gray, + Black, + Red, + Maroon, + Yellow, + Olive, + Lime, + Green, + Cyan, + Teal, + Blue, + Navy, + Magenta, + Purple, + Orange }; struct PineTimeStyle { Colors ColorTime = Colors::Teal; @@ -146,18 +162,29 @@ namespace Pinetime { } settings.brightLevel = level; }; + Controllers::BrightnessController::Levels GetBrightness() const { return settings.brightLevel; }; - void SetStepsGoal( uint32_t goal ) { - if ( goal != settings.stepsGoal ) { + void SetStepsGoal(uint32_t goal) { + if (goal != settings.stepsGoal) { settingsChanged = true; } settings.stepsGoal = goal; }; - uint32_t GetStepsGoal() const { return settings.stepsGoal; }; + uint32_t GetStepsGoal() const { + return settings.stepsGoal; + }; + + void SetAirplaneMode(bool mode) { + airplaneMode = mode; + }; + + bool GetAirplaneMode() const { + return airplaneMode; + }; private: Pinetime::Controllers::FS& fs; @@ -185,6 +212,10 @@ namespace Pinetime { uint8_t appMenu = 0; uint8_t settingsMenu = 0; + /* airplaneMode is intentionally not saved with the other watch settings and initialized + * to off (false) on every boot because we always want ble to be enabled on startup + */ + bool airplaneMode = false; void LoadSettingsFromFile(); void SaveSettingsToFile(); diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index b2f55ccdc8..971c36b76e 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -37,7 +37,8 @@ namespace Pinetime { SettingPineTimeStyle, SettingSetDate, SettingSetTime, - Error, + SettingAirplaneMode, + Error }; } } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 233f433dd2..d3896b18ea 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -48,6 +48,7 @@ #include "displayapp/screens/settings/SettingPineTimeStyle.h" #include "displayapp/screens/settings/SettingSetDate.h" #include "displayapp/screens/settings/SettingSetTime.h" +#include "displayapp/screens/settings/SettingAirplaneMode.h" #include "libs/lv_conf.h" @@ -289,6 +290,9 @@ void DisplayApp::Refresh() { case Messages::BleFirmwareUpdateStarted: LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); break; + case Messages::AirplaneModeToggle: + PushMessageToSystemTask(System::Messages::AirplaneModeToggle); + break; case Messages::UpdateDateTime: // Added to remove warning // What should happen here? @@ -420,6 +424,10 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentScreen = std::make_unique(this, settingsController); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; + case Apps::SettingAirplaneMode: + currentScreen = std::make_unique(this, settingsController); + ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); + break; case Apps::BatteryInfo: currentScreen = std::make_unique(this, batteryController); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index b22d6c3cf9..4d52df2055 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -20,7 +20,8 @@ namespace Pinetime { DimScreen, RestoreBrightness, ShowPairingKey, - AlarmTriggered + AlarmTriggered, + AirplaneModeToggle }; } } diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index 8a26084613..40ecd3e259 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -13,7 +13,7 @@ * Do not enable font compression and horizontal subpixel hinting * Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7f, 0x410-0x44f` * Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following - range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015` + range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf072` * Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts` * Add the font .c file path to src/CMakeLists.txt * Add an LV_FONT_DECLARE line in src/libs/lv_conf.h diff --git a/src/displayapp/fonts/jetbrains_mono_bold_20.c b/src/displayapp/fonts/jetbrains_mono_bold_20.c index d8705528ce..944e47a1dc 100644 --- a/src/displayapp/fonts/jetbrains_mono_bold_20.c +++ b/src/displayapp/fonts/jetbrains_mono_bold_20.c @@ -840,6 +840,16 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xf8, 0xf, 0x80, 0xf8, 0x3e, 0x0, 0xff, 0xf0, 0x0, 0x3f, 0x80, 0x0, + /* U+F072 "" */ + 0x1, 0xc0, 0x0, 0x7, 0xc0, 0x0, 0x7, 0x80, + 0x0, 0xf, 0x80, 0x0, 0x1f, 0x0, 0x0, 0x1f, + 0x0, 0x38, 0x3e, 0x0, 0x78, 0x7e, 0x0, 0x7f, + 0xff, 0xe0, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf3, + 0xff, 0xff, 0xe7, 0xff, 0xff, 0xdf, 0xff, 0xfc, + 0x3c, 0x3f, 0x0, 0x70, 0x7c, 0x0, 0x1, 0xf0, + 0x0, 0x3, 0xe0, 0x0, 0x7, 0x80, 0x0, 0xf, + 0x0, 0x0, 0x1c, 0x0, 0x0, + /* U+F095 "" */ 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x7, 0xf0, 0x0, 0x7f, 0x0, 0x7, 0xf0, 0x0, 0xff, 0x0, @@ -1220,31 +1230,32 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 3028, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, {.bitmap_index = 3056, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, {.bitmap_index = 3104, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 3148, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3201, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3220, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3270, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3306, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3354, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 3394, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3437, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3475, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3513, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3551, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3589, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3627, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3663, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, - {.bitmap_index = 3701, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3730, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 3768, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3834, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3883, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3933, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3993, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 4046, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 4107, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4162, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4215, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} + {.bitmap_index = 3148, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3209, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3262, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3281, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3331, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3367, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3415, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3455, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3498, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3536, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3574, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3612, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3650, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3688, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3724, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3762, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3791, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 3829, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3895, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3944, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3994, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4054, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4107, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4168, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4223, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4276, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} }; /*--------------------- @@ -1253,10 +1264,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { static const uint16_t unicode_list_2[] = { 0x0, 0x14, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39, - 0x47, 0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x6d, 0x94, - 0x128, 0x184, 0x1e5, 0x1fb, 0x200, 0x21d, 0x23f, 0x240, - 0x241, 0x242, 0x243, 0x251, 0x292, 0x293, 0x2f1, 0x3dc, - 0x3fc, 0x45c, 0x54a, 0x55f, 0x568, 0x59e, 0x59f, 0x6a8 + 0x47, 0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x6d, 0x71, + 0x94, 0x128, 0x184, 0x1e5, 0x1fb, 0x200, 0x21d, 0x23f, + 0x240, 0x241, 0x242, 0x243, 0x251, 0x292, 0x293, 0x2f1, + 0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f, 0x568, 0x59e, 0x59f, + 0x6a8 }; /*Collect the unicode lists and glyph_id offsets*/ @@ -1272,7 +1284,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] = }, { .range_start = 61441, .range_length = 1705, .glyph_id_start = 160, - .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 40, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY + .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 41, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY } }; @@ -1321,7 +1333,7 @@ lv_font_t jetbrains_mono_bold_20 = { #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, #endif -#if LV_VERSION_CHECK(7, 4, 0) +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 .underline_position = -3, .underline_thickness = 1, #endif diff --git a/src/displayapp/screens/BleIcon.cpp b/src/displayapp/screens/BleIcon.cpp index 5058f3eb84..a30d23bdfe 100644 --- a/src/displayapp/screens/BleIcon.cpp +++ b/src/displayapp/screens/BleIcon.cpp @@ -2,9 +2,11 @@ #include "displayapp/screens/Symbols.h" using namespace Pinetime::Applications::Screens; -const char* BleIcon::GetIcon(bool isConnected) { - if (isConnected) +const char* BleIcon::GetIcon(Pinetime::Controllers::Ble::ConnectStates state) { + if (state == Pinetime::Controllers::Ble::ConnectStates::Connected) return Symbols::bluetooth; + else if (state == Pinetime::Controllers::Ble::ConnectStates::Airplane) + return Symbols::airplane; else - return ""; -} \ No newline at end of file + return Symbols::none; +} diff --git a/src/displayapp/screens/BleIcon.h b/src/displayapp/screens/BleIcon.h index c1398d2a68..d7410eae2f 100644 --- a/src/displayapp/screens/BleIcon.h +++ b/src/displayapp/screens/BleIcon.h @@ -1,12 +1,14 @@ #pragma once +#include "components/ble/BleController.h" + namespace Pinetime { namespace Applications { namespace Screens { class BleIcon { public: - static const char* GetIcon(bool isConnected); + static const char* GetIcon(Pinetime::Controllers::Ble::ConnectStates state); }; } } -} \ No newline at end of file +} diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp index d4368691ab..e7b1f39397 100644 --- a/src/displayapp/screens/PineTimeStyle.cpp +++ b/src/displayapp/screens/PineTimeStyle.cpp @@ -208,10 +208,10 @@ void PineTimeStyle::SetBatteryIcon() { } void PineTimeStyle::AlignIcons() { - if (notificationState.Get() && bleState.Get()) { + if (notificationState.Get() && bleState.Get() != Pinetime::Controllers::Ble::ConnectStates::Disconnected) { lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 8, 25); lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, -8, 25); - } else if (notificationState.Get() && !bleState.Get()) { + } else if (notificationState.Get() && bleState.Get() == Pinetime::Controllers::Ble::ConnectStates::Disconnected) { lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); } else { lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); @@ -234,7 +234,7 @@ void PineTimeStyle::Refresh() { } } - bleState = bleController.IsConnected(); + bleState = bleController.GetConnectState(); if (bleState.IsUpdated()) { lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); AlignIcons(); diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h index 8382c53c26..c5136fc20c 100644 --- a/src/displayapp/screens/PineTimeStyle.h +++ b/src/displayapp/screens/PineTimeStyle.h @@ -6,6 +6,7 @@ #include #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" +#include "components/ble/BleController.h" namespace Pinetime { namespace Controllers { @@ -36,13 +37,13 @@ namespace Pinetime { char displayedChar[5]; uint16_t currentYear = 1970; - Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; - Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; + Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; + Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; uint8_t currentDay = 0; DirtyValue batteryPercentRemaining {}; DirtyValue isCharging {}; - DirtyValue bleState {}; + DirtyValue bleState {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; DirtyValue stepCount {}; diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index e68a7af6b2..5ba8f95352 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -44,6 +44,7 @@ namespace Pinetime { static constexpr const char* chartLine = "\xEF\x88\x81"; static constexpr const char* eye = "\xEF\x81\xAE"; static constexpr const char* home = "\xEF\x80\x95"; + static constexpr const char* airplane = "\xEF\x81\xB2"; // lv_font_sys_48.c static constexpr const char* settings = "\xEE\xA4\x82"; // e902 diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 876957938d..8f06553fb7 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -119,7 +119,7 @@ void WatchFaceDigital::Refresh() { lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); } - bleState = bleController.IsConnected(); + bleState = bleController.GetConnectState(); if (bleState.IsUpdated()) { lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); } diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 627154c818..addb539ae0 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -6,6 +6,7 @@ #include #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" +#include "components/ble/BleController.h" namespace Pinetime { namespace Controllers { @@ -38,13 +39,13 @@ namespace Pinetime { char displayedChar[5] {}; uint16_t currentYear = 1970; - Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; - Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; + Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; + Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; uint8_t currentDay = 0; DirtyValue batteryPercentRemaining {}; DirtyValue powerPresent {}; - DirtyValue bleState {}; + DirtyValue bleState {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; DirtyValue stepCount {}; diff --git a/src/displayapp/screens/settings/SettingAirplaneMode.cpp b/src/displayapp/screens/settings/SettingAirplaneMode.cpp new file mode 100644 index 0000000000..0a364ded59 --- /dev/null +++ b/src/displayapp/screens/settings/SettingAirplaneMode.cpp @@ -0,0 +1,89 @@ +#include "displayapp/screens/settings/SettingAirplaneMode.h" +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/Messages.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + static void event_handler(lv_obj_t* obj, lv_event_t event) { + SettingAirplaneMode* screen = static_cast(obj->user_data); + screen->UpdateSelected(obj, event); + } +} + +constexpr std::array SettingAirplaneMode::options; + +SettingAirplaneMode::SettingAirplaneMode(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, "Airplane mode"); + 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::airplane); + 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]); + } + + if (settingsController.GetAirplaneMode() == false) { + lv_checkbox_set_checked(cbOption[0], true); + priorMode = false; + } else { + lv_checkbox_set_checked(cbOption[1], true); + priorMode = true; + } +} + +SettingAirplaneMode::~SettingAirplaneMode() { + lv_obj_clean(lv_scr_act()); + // Do not call SaveSettings - see src/components/settings/Settings.h + if (priorMode != settingsController.GetAirplaneMode()) { + app->PushMessage(Pinetime::Applications::Display::Messages::AirplaneModeToggle); + } +} + +void SettingAirplaneMode::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.SetAirplaneMode(false); + }; + if (i == 1) { + settingsController.SetAirplaneMode(true); + }; + + } else { + lv_checkbox_set_checked(cbOption[i], false); + } + } + } +} diff --git a/src/displayapp/screens/settings/SettingAirplaneMode.h b/src/displayapp/screens/settings/SettingAirplaneMode.h new file mode 100644 index 0000000000..fcc0222865 --- /dev/null +++ b/src/displayapp/screens/settings/SettingAirplaneMode.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +#include "components/settings/Settings.h" +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingAirplaneMode : public Screen { + public: + SettingAirplaneMode(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); + ~SettingAirplaneMode() override; + + void UpdateSelected(lv_obj_t* object, lv_event_t event); + + private: + static constexpr std::array options = {" No", " Yes"}; + Controllers::Settings& settingsController; + lv_obj_t* cbOption[options.size()]; + bool priorMode; + }; + } + } +} diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp index 392c12e052..6be00f5780 100644 --- a/src/displayapp/screens/settings/Settings.cpp +++ b/src/displayapp/screens/settings/Settings.cpp @@ -36,10 +36,10 @@ bool Settings::OnTouchEvent(Pinetime::Applications::TouchEvents event) { std::unique_ptr Settings::CreateScreen1() { std::array applications {{ - {Symbols::sun, "Display", Apps::SettingDisplay}, - {Symbols::eye, "Wake Up", Apps::SettingWakeUp}, - {Symbols::clock, "Time format", Apps::SettingTimeFormat}, - {Symbols::home, "Watch face", Apps::SettingWatchFace}, + {Symbols::list, "About", Apps::SysInfo}, + {Symbols::airplane, "Airplane mode", Apps::SettingAirplaneMode}, + {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, + {Symbols::sun, "Display", Apps::SettingDisplay} }}; return std::make_unique(0, 3, app, settingsController, applications); @@ -48,10 +48,10 @@ std::unique_ptr Settings::CreateScreen1() { std::unique_ptr Settings::CreateScreen2() { std::array applications {{ - {Symbols::shoe, "Steps", Apps::SettingSteps}, + {Symbols::check, "Firmware", Apps::FirmwareValidation}, + {Symbols::paintbrush, "PTS colors", Apps::SettingPineTimeStyle}, {Symbols::clock, "Set date", Apps::SettingSetDate}, - {Symbols::clock, "Set time", Apps::SettingSetTime}, - {Symbols::batteryHalf, "Battery", Apps::BatteryInfo} + {Symbols::clock, "Set time", Apps::SettingSetTime} }}; return std::make_unique(1, 3, app, settingsController, applications); @@ -60,10 +60,10 @@ std::unique_ptr Settings::CreateScreen2() { std::unique_ptr Settings::CreateScreen3() { std::array applications {{ - {Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle}, - {Symbols::check, "Firmware", Apps::FirmwareValidation}, - {Symbols::list, "About", Apps::SysInfo}, - {Symbols::none, "None", Apps::None}, + {Symbols::shoe, "Steps", Apps::SettingSteps}, + {Symbols::clock, "Time format", Apps::SettingTimeFormat}, + {Symbols::eye, "Wake up", Apps::SettingWakeUp}, + {Symbols::home, "Watch face", Apps::SettingWatchFace} }}; return std::make_unique(2, 3, app, settingsController, applications); diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index cc30fdc682..886505b536 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -29,6 +29,7 @@ namespace Pinetime { BatteryPercentageUpdated, StartFileTransfer, StopFileTransfer, + AirplaneModeToggle }; } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index a95d479dec..5ce223a6ab 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -261,7 +261,7 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning); heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp); - if (!bleController.IsConnected()) { + if (bleController.GetConnectState() == Controllers::Ble::ConnectStates::Disconnected) { nimbleController.RestartFastAdv(); } @@ -424,7 +424,9 @@ void SystemTask::Work() { motorController.RunForDuration(35); displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowPairingKey); break; - + case Messages::AirplaneModeToggle: + nimbleController.SwitchAirplaneMode(settingsController.GetAirplaneMode()); + break; default: break; } From 5e6868d9eb0957eeaaeb34269a7614a0a3f417e8 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sat, 1 Jan 2022 16:22:35 +0200 Subject: [PATCH 05/78] Improved notification timeout --- src/displayapp/DisplayApp.cpp | 4 +- src/displayapp/screens/Notifications.cpp | 52 +++++++++++++++++------- src/displayapp/screens/Notifications.h | 10 ++++- src/systemtask/SystemTask.cpp | 1 + 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 2354107b83..383badf1c9 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -362,12 +362,12 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Notifications: currentScreen = std::make_unique( - this, notificationManager, systemTask->nimble().alertService(), motorController, Screens::Notifications::Modes::Normal); + this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Normal); ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::NotificationsPreview: currentScreen = std::make_unique( - this, notificationManager, systemTask->nimble().alertService(), motorController, Screens::Notifications::Modes::Preview); + this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Preview); ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::Timer: diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 569c422b59..8fe08a826d 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -12,8 +12,13 @@ Notifications::Notifications(DisplayApp* app, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController, + System::SystemTask& systemTask, Modes mode) - : Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, mode {mode} { + : Screen(app), + notificationManager {notificationManager}, + alertNotificationService {alertNotificationService}, + systemTask {systemTask}, + mode {mode} { notificationManager.ClearNewNotificationFlag(); auto notification = notificationManager.GetLastNotification(); if (notification.valid) { @@ -37,20 +42,22 @@ Notifications::Notifications(DisplayApp* app, } if (mode == Modes::Preview) { + systemTask.PushMessage(System::Messages::DisableSleeping); if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) { motorController.StartRinging(); } else { motorController.RunForDuration(35); - timeoutLine = lv_line_create(lv_scr_act(), nullptr); + } - lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); - lv_obj_set_style_local_line_color(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_obj_set_style_local_line_rounded(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true); + timeoutLine = lv_line_create(lv_scr_act(), nullptr); - lv_line_set_points(timeoutLine, timeoutLinePoints, 2); - timeoutTickCountStart = xTaskGetTickCount(); - timeoutTickCountEnd = timeoutTickCountStart + (5 * 1024); - } + lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_line_color(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_line_rounded(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true); + + lv_line_set_points(timeoutLine, timeoutLinePoints, 2); + timeoutTickCountStart = xTaskGetTickCount(); + interacted = false; } taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -60,23 +67,40 @@ Notifications::~Notifications() { lv_task_del(taskRefresh); // make sure we stop any vibrations before exiting Controllers::MotorController::StopRinging(); + systemTask.PushMessage(System::Messages::EnableSleeping); lv_obj_clean(lv_scr_act()); } void Notifications::Refresh() { if (mode == Modes::Preview && timeoutLine != nullptr) { - auto tick = xTaskGetTickCount(); - int32_t pos = 240 - ((tick - timeoutTickCountStart) / ((timeoutTickCountEnd - timeoutTickCountStart) / 240)); - if (pos < 0) + TickType_t tick = xTaskGetTickCount(); + int32_t pos = 240 - ((tick - timeoutTickCountStart) / (timeoutLength / 240)); + if (pos <= 0) { running = false; + } else { + timeoutLinePoints[1].x = pos; + lv_line_set_points(timeoutLine, timeoutLinePoints, 2); + } + } + running = currentItem->IsRunning() && running; +} - timeoutLinePoints[1].x = pos; - lv_line_set_points(timeoutLine, timeoutLinePoints, 2); +void Notifications::OnPreviewInteraction() { + systemTask.PushMessage(System::Messages::EnableSleeping); + Controllers::MotorController::StopRinging(); + if (timeoutLine != nullptr) { + lv_obj_del(timeoutLine); + timeoutLine = nullptr; } } bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { if (mode != Modes::Normal) { + if (!interacted && event == TouchEvents::Tap) { + interacted = true; + OnPreviewInteraction(); + return true; + } return false; } diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index cbb7af6ce5..2f444c7ce9 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -1,11 +1,13 @@ #pragma once #include +#include #include #include #include "displayapp/screens/Screen.h" #include "components/ble/NotificationManager.h" #include "components/motor/MotorController.h" +#include "systemtask/SystemTask.h" namespace Pinetime { namespace Controllers { @@ -21,11 +23,13 @@ namespace Pinetime { Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController, + System::SystemTask& systemTask, Modes mode); ~Notifications() override; void Refresh() override; bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; + void OnPreviewInteraction(); class NotificationItem { public: @@ -62,6 +66,7 @@ namespace Pinetime { }; Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::AlertNotificationService& alertNotificationService; + System::SystemTask& systemTask; Modes mode = Modes::Normal; std::unique_ptr currentItem; Controllers::NotificationManager::Notification::Id currentId; @@ -69,8 +74,9 @@ namespace Pinetime { lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}}; lv_obj_t* timeoutLine = nullptr; - uint32_t timeoutTickCountStart; - uint32_t timeoutTickCountEnd; + TickType_t timeoutTickCountStart; + static const TickType_t timeoutLength = pdMS_TO_TICKS(7000); + bool interacted = true; lv_task_t* taskRefresh; }; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index a95d479dec..0eb0761883 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -239,6 +239,7 @@ void SystemTask::Work() { if (!bleController.IsFirmwareUpdating()) { doNotGoToSleep = false; } + ReloadIdleTimer(); break; case Messages::DisableSleeping: doNotGoToSleep = true; From 48e9458301f7503da12b90046427c883c3d0c92b Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 16 Jan 2022 20:45:57 +0100 Subject: [PATCH 06/78] ButtonHandler: includes relative to src dir --- src/buttonhandler/ButtonHandler.cpp | 2 +- src/buttonhandler/ButtonHandler.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/buttonhandler/ButtonHandler.cpp b/src/buttonhandler/ButtonHandler.cpp index 02ee22cf72..3c2bc72cf1 100644 --- a/src/buttonhandler/ButtonHandler.cpp +++ b/src/buttonhandler/ButtonHandler.cpp @@ -1,4 +1,4 @@ -#include "ButtonHandler.h" +#include "buttonhandler/ButtonHandler.h" using namespace Pinetime::Controllers; diff --git a/src/buttonhandler/ButtonHandler.h b/src/buttonhandler/ButtonHandler.h index 44b20f19ef..5802b998cf 100644 --- a/src/buttonhandler/ButtonHandler.h +++ b/src/buttonhandler/ButtonHandler.h @@ -1,6 +1,6 @@ #pragma once -#include "ButtonActions.h" +#include "buttonhandler/ButtonActions.h" #include "systemtask/SystemTask.h" #include #include From bbc5af078d91a70f757173441a79077164cc372d Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 16 Jan 2022 22:39:07 +0100 Subject: [PATCH 07/78] SystemTask: add missing queue.h include for QueueHandle_t --- src/systemtask/SystemTask.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index e2e6de7f66..abeffd2f9e 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include From 688dc2fed7b207bdf80b5f4af5a5df8faad9f2ec Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 17 Jan 2022 21:25:16 +0100 Subject: [PATCH 08/78] Create Version.h in binary dir instead of src dir Don't use source directory for generated files. Use the binary (build) directory instead. --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2e0a11475..8846531e8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ else() endif() set(VERSION_EDIT_WARNING "// Do not edit this file, it is automatically generated by CMAKE!") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docker/post_build.sh.in ${CMAKE_CURRENT_BINARY_DIR}/post_build.sh) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 062d8a5000..aec6ce047f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -612,6 +612,7 @@ list(APPEND RECOVERYLOADER_SOURCE_FILES set(INCLUDE_FILES + ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h BootloaderVersion.h logging/Logger.h logging/NrfLogger.h @@ -710,6 +711,7 @@ set(INCLUDE_FILES ) include_directories( + ${CMAKE_BINARY_DIR}/src # include generated files like Version.h . ../ libs/ From 6bf6bb7e2a9e636f496341419a12a7720b3d4dac Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Thu, 20 Jan 2022 16:04:26 +0200 Subject: [PATCH 09/78] PTS and digital watchface code cleanups --- src/displayapp/screens/PineTimeStyle.cpp | 88 +++++++---------- src/displayapp/screens/PineTimeStyle.h | 3 +- src/displayapp/screens/WatchFaceDigital.cpp | 103 ++++++++------------ src/displayapp/screens/WatchFaceDigital.h | 3 +- 4 files changed, 79 insertions(+), 118 deletions(-) diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp index b2b972dc38..7ce0bc0d08 100644 --- a/src/displayapp/screens/PineTimeStyle.cpp +++ b/src/displayapp/screens/PineTimeStyle.cpp @@ -60,12 +60,6 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, settingsController {settingsController}, motionController {motionController} { - displayedChar[0] = 0; - displayedChar[1] = 0; - displayedChar[2] = 0; - displayedChar[3] = 0; - displayedChar[4] = 0; - // Create a 200px wide background rectangle timebar = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_color(timebar, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorBG())); @@ -77,19 +71,19 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, timeDD1 = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light); lv_obj_set_style_local_text_color(timeDD1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); - lv_label_set_text(timeDD1, "00"); + lv_label_set_text_static(timeDD1, "00"); lv_obj_align(timeDD1, timebar, LV_ALIGN_IN_TOP_MID, 5, 5); timeDD2 = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &open_sans_light); lv_obj_set_style_local_text_color(timeDD2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); - lv_label_set_text(timeDD2, "00"); + lv_label_set_text_static(timeDD2, "00"); lv_obj_align(timeDD2, timebar, LV_ALIGN_IN_BOTTOM_MID, 5, -5); timeAMPM = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime())); lv_obj_set_style_local_text_line_space(timeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, -3); - lv_label_set_text(timeAMPM, ""); + lv_label_set_text_static(timeAMPM, ""); lv_obj_align(timeAMPM, timebar, LV_ALIGN_IN_BOTTOM_LEFT, 2, -20); // Create a 40px wide bar down the right side of the screen @@ -102,17 +96,17 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, // Display icons batteryIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_label_set_text(batteryIcon, Symbols::batteryFull); + lv_label_set_text_static(batteryIcon, Symbols::batteryFull); lv_obj_align(batteryIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2); lv_obj_set_auto_realign(batteryIcon, true); bleIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); - lv_label_set_text(bleIcon, ""); + lv_label_set_text_static(bleIcon, ""); notificationIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000)); - lv_label_set_text(notificationIcon, ""); + lv_label_set_text_static(notificationIcon, ""); // Calendar icon calendarOuter = lv_obj_create(lv_scr_act(), nullptr); @@ -154,17 +148,17 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, // Display date dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_label_set_text(dateDayOfWeek, "THU"); + lv_label_set_text_static(dateDayOfWeek, "THU"); lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34); dateDay = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_label_set_text(dateDay, "25"); + lv_label_set_text_static(dateDay, "25"); lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3); dateMonth = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(dateMonth, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_label_set_text(dateMonth, "MAR"); + lv_label_set_text_static(dateMonth, "MAR"); lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32); // Step count gauge @@ -199,7 +193,7 @@ PineTimeStyle::PineTimeStyle(DisplayApp* app, lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); lv_obj_set_size(backgroundLabel, 240, 240); lv_obj_set_pos(backgroundLabel, 0, 0); - lv_label_set_text(backgroundLabel, ""); + lv_label_set_text_static(backgroundLabel, ""); btnNextTime = lv_btn_create(lv_scr_act(), nullptr); btnNextTime->user_data = this; @@ -339,7 +333,7 @@ bool PineTimeStyle::OnButtonPushed() { void PineTimeStyle::SetBatteryIcon() { auto batteryPercent = batteryPercentRemaining.Get(); - lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); + lv_label_set_text_static(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); } void PineTimeStyle::AlignIcons() { @@ -357,7 +351,7 @@ void PineTimeStyle::Refresh() { isCharging = batteryController.IsCharging(); if (isCharging.IsUpdated()) { if (isCharging.Get()) { - lv_label_set_text(batteryIcon, Symbols::plug); + lv_label_set_text_static(batteryIcon, Symbols::plug); } else { SetBatteryIcon(); } @@ -371,13 +365,13 @@ void PineTimeStyle::Refresh() { bleState = bleController.IsConnected(); if (bleState.IsUpdated()) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); + lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); AlignIcons(); } notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); AlignIcons(); } @@ -394,45 +388,31 @@ void PineTimeStyle::Refresh() { auto day = static_cast(yearMonthDay.day()); auto dayOfWeek = static_cast(date::weekday(yearMonthDay).iso_encoding()); - int hour = time.hours().count(); - auto minute = time.minutes().count(); - - char minutesChar[3]; - sprintf(minutesChar, "%02d", static_cast(minute)); - - char hoursChar[3]; - char ampmChar[5]; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - sprintf(hoursChar, "%02d", hour); - } else { - if (hour == 0 && hour != 12) { - hour = 12; - sprintf(ampmChar, "A\nM"); - } else if (hour == 12 && hour != 0) { - hour = 12; - sprintf(ampmChar, "P\nM"); - } else if (hour < 12 && hour != 0) { - sprintf(ampmChar, "A\nM"); - } else if (hour > 12 && hour != 0) { - hour = hour - 12; - sprintf(ampmChar, "P\nM"); - } - sprintf(hoursChar, "%02d", hour); - } + uint8_t hour = time.hours().count(); + uint8_t minute = time.minutes().count(); - if (hoursChar[0] != displayedChar[0] or hoursChar[1] != displayedChar[1] or minutesChar[0] != displayedChar[2] or - minutesChar[1] != displayedChar[3]) { - displayedChar[0] = hoursChar[0]; - displayedChar[1] = hoursChar[1]; - displayedChar[2] = minutesChar[0]; - displayedChar[3] = minutesChar[1]; + if (displayedHour != hour || displayedMinute != minute) { + displayedHour = hour; + displayedMinute = minute; if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + char ampmChar[4] = "A\nM"; + if (hour == 0) { + hour = 12; + } else if (hour == 12) { + ampmChar[0] = 'P'; + } else if (hour > 12) { + hour = hour - 12; + ampmChar[0] = 'P'; + } lv_label_set_text(timeAMPM, ampmChar); + // Should be padded with blank spaces, but the space character doesn't exist in the font + lv_label_set_text_fmt(timeDD1, "%02d", hour); + lv_label_set_text_fmt(timeDD2, "%02d", minute); + } else { + lv_label_set_text_fmt(timeDD1, "%02d", hour); + lv_label_set_text_fmt(timeDD2, "%02d", minute); } - - lv_label_set_text_fmt(timeDD1, "%s", hoursChar); - lv_label_set_text_fmt(timeDD2, "%s", minutesChar); } if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h index df8b7d5abb..1b972ce1ba 100644 --- a/src/displayapp/screens/PineTimeStyle.h +++ b/src/displayapp/screens/PineTimeStyle.h @@ -39,7 +39,8 @@ namespace Pinetime { void UpdateSelected(lv_obj_t *object, lv_event_t event); private: - char displayedChar[5]; + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; uint16_t currentYear = 1970; Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 4d9eaf3722..b3cb0f917a 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -35,22 +35,22 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app, settingsController.SetClockFace(0); batteryIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text(batteryIcon, Symbols::batteryFull); + lv_label_set_text_static(batteryIcon, Symbols::batteryFull); lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0); batteryPlug = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); - lv_label_set_text(batteryPlug, Symbols::plug); + lv_label_set_text_static(batteryPlug, Symbols::plug); lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); bleIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC)); - lv_label_set_text(bleIcon, Symbols::bluetooth); + lv_label_set_text_static(bleIcon, Symbols::bluetooth); lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0); notificationIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00)); - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); label_date = lv_label_create(lv_scr_act(), nullptr); @@ -71,26 +71,26 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app, lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); lv_obj_set_size(backgroundLabel, 240, 240); lv_obj_set_pos(backgroundLabel, 0, 0); - lv_label_set_text(backgroundLabel, ""); + lv_label_set_text_static(backgroundLabel, ""); heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text(heartbeatIcon, Symbols::heartBeat); + lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); heartbeatValue = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); - lv_label_set_text(heartbeatValue, ""); + lv_label_set_text_static(heartbeatValue, ""); lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); stepValue = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); - lv_label_set_text(stepValue, "0"); + lv_label_set_text_static(stepValue, "0"); lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); stepIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); - lv_label_set_text(stepIcon, Symbols::shoe); + lv_label_set_text_static(stepIcon, Symbols::shoe); lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -105,7 +105,7 @@ WatchFaceDigital::~WatchFaceDigital() { void WatchFaceDigital::Refresh() { powerPresent = batteryController.IsPowerPresent(); if (powerPresent.IsUpdated()) { - lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get())); + lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get())); } batteryPercentRemaining = batteryController.PercentRemaining(); @@ -116,20 +116,20 @@ void WatchFaceDigital::Refresh() { } else { lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); } - lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); + lv_label_set_text_static(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); } bleState = bleController.IsConnected(); if (bleState.IsUpdated()) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); + lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); } - lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0); - lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); - lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0); + lv_obj_realign(batteryIcon); + lv_obj_realign(batteryPlug); + lv_obj_realign(bleIcon); notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); } currentDateTime = dateTimeController.CurrentDateTime(); @@ -146,62 +146,41 @@ void WatchFaceDigital::Refresh() { auto day = static_cast(yearMonthDay.day()); auto dayOfWeek = static_cast(date::weekday(yearMonthDay).iso_encoding()); - int hour = time.hours().count(); - auto minute = time.minutes().count(); - - char minutesChar[3]; - sprintf(minutesChar, "%02d", static_cast(minute)); - - char hoursChar[3]; - char ampmChar[3]; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - sprintf(hoursChar, "%02d", hour); - } else { - if (hour == 0 && hour != 12) { - hour = 12; - sprintf(ampmChar, "AM"); - } else if (hour == 12 && hour != 0) { - hour = 12; - sprintf(ampmChar, "PM"); - } else if (hour < 12 && hour != 0) { - sprintf(ampmChar, "AM"); - } else if (hour > 12 && hour != 0) { - hour = hour - 12; - sprintf(ampmChar, "PM"); - } - sprintf(hoursChar, "%02d", hour); - } + uint8_t hour = time.hours().count(); + uint8_t minute = time.minutes().count(); - if ((hoursChar[0] != displayedChar[0]) or (hoursChar[1] != displayedChar[1]) or (minutesChar[0] != displayedChar[2]) or - (minutesChar[1] != displayedChar[3])) { - displayedChar[0] = hoursChar[0]; - displayedChar[1] = hoursChar[1]; - displayedChar[2] = minutesChar[0]; - displayedChar[3] = minutesChar[1]; + if (displayedHour != hour || displayedMinute != minute) { + displayedHour = hour; + displayedMinute = minute; if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - lv_label_set_text(label_time_ampm, ampmChar); - if (hoursChar[0] == '0') { - hoursChar[0] = ' '; + char ampmChar[3] = "AM"; + if (hour == 0) { + hour = 12; + } else if (hour == 12) { + ampmChar[0] = 'P'; + } else if (hour > 12) { + hour = hour - 12; + ampmChar[0] = 'P'; } - } - - lv_label_set_text_fmt(label_time, "%s:%s", hoursChar, minutesChar); - - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + lv_label_set_text(label_time_ampm, ampmChar); + lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute); lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); } else { + lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute); lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); } } if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - lv_label_set_text_fmt(label_date, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year); + lv_label_set_text_fmt( + label_date, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year); } else { - lv_label_set_text_fmt(label_date, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year); + lv_label_set_text_fmt( + label_date, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year); } - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); + lv_obj_realign(label_date); currentYear = year; currentMonth = month; @@ -221,15 +200,15 @@ void WatchFaceDigital::Refresh() { lv_label_set_text_static(heartbeatValue, ""); } - lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); + lv_obj_realign(heartbeatIcon); + lv_obj_realign(heartbeatValue); } stepCount = motionController.NbSteps(); motionSensorOk = motionController.IsSensorOk(); if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) { lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get()); - lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); + lv_obj_realign(stepValue); + lv_obj_realign(stepIcon); } } diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 627154c818..ab3a028599 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -35,7 +35,8 @@ namespace Pinetime { void Refresh() override; private: - char displayedChar[5] {}; + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; uint16_t currentYear = 1970; Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; From 470db4ab99c214001b3064cfaad135b2b3b6c584 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sat, 22 Jan 2022 12:47:23 +0200 Subject: [PATCH 10/78] Fix alarm on time change --- src/components/datetime/DateTimeController.cpp | 2 ++ src/systemtask/SystemTask.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index 673903cb5b..97ccbe38e0 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -36,6 +36,8 @@ void DateTime::SetTime( UpdateTime(systickCounter); NRF_LOG_INFO("* %d %d %d ", this->hour, this->minute, this->second); NRF_LOG_INFO("* %d %d %d ", this->day, this->month, this->year); + + systemTask->PushMessage(System::Messages::OnNewTime); } void DateTime::UpdateTime(uint32_t systickCounter) { diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 94d40c997d..d44945527e 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -295,6 +295,9 @@ void SystemTask::Work() { case Messages::OnNewTime: ReloadIdleTimer(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateDateTime); + if (alarmController.State() == Controllers::AlarmController::AlarmState::Set) { + alarmController.ScheduleAlarm(); + } break; case Messages::OnNewNotification: if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) { From 314c02194a19016d83fb71a41f6f647959b7be1e Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 23 Jan 2022 23:34:25 +0100 Subject: [PATCH 11/78] Music: initialize totalLength to have non-random data from the start In the first `Music::Refresh` call the lastLength and totalLength are not initialized. The `lastLength` value is read first from the musicService. Naturally in the first itereation that is changed and `UpdateLength()` is called. There the variable `totalLength` is used as well, but that variable isn't initialed to a sensible value yet. This leads to sometimes the `Music.h` screen segfaulting (depending on the random uninitialized data in the `lastLength` variable) --- src/displayapp/screens/Music.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index f9b4eaabfb..35f7bab552 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -69,7 +69,7 @@ namespace Pinetime { std::string track; /** Total length in seconds */ - int totalLength; + int totalLength = 0; /** Current length in seconds */ int currentLength; /** Last length */ From b4e956227e69d29e9440e3b125521c4f8d23d649 Mon Sep 17 00:00:00 2001 From: hatmajster Date: Mon, 24 Jan 2022 20:28:05 +0100 Subject: [PATCH 12/78] Hrs3300: changed default gain to x8 --- src/drivers/Hrs3300.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/Hrs3300.cpp b/src/drivers/Hrs3300.cpp index c14fe7aa7d..9d71253d50 100644 --- a/src/drivers/Hrs3300.cpp +++ b/src/drivers/Hrs3300.cpp @@ -36,8 +36,8 @@ void Hrs3300::Init() { // HRS and ALS both in 16-bit mode WriteRegister(static_cast(Registers::Res), 0x88); - // 64x gain - WriteRegister(static_cast(Registers::Hgain), 0x10); + // 8x gain, non default, reduced value for better readings + WriteRegister(static_cast(Registers::Hgain), 0xc); } void Hrs3300::Enable() { From 67f546fa330f7bbe251bfde432b36284db1a79dd Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 24 Jan 2022 23:03:08 +0100 Subject: [PATCH 13/78] StopWatch: cleanup unused includes and use relative to src includes --- src/displayapp/screens/StopWatch.cpp | 9 +++------ src/displayapp/screens/StopWatch.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index a260d29310..8749839f7d 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -1,13 +1,10 @@ -#include "StopWatch.h" +#include "displayapp/screens/StopWatch.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" #include -#include "projdefs.h" -#include "FreeRTOSConfig.h" -#include "task.h" - -#include +#include +#include using namespace Pinetime::Applications::Screens; diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h index 0720a5868d..06193f6886 100644 --- a/src/displayapp/screens/StopWatch.h +++ b/src/displayapp/screens/StopWatch.h @@ -4,7 +4,7 @@ #include "components/datetime/DateTimeController.h" #include "displayapp/LittleVgl.h" -#include "FreeRTOS.h" +#include #include "portmacro_cmsis.h" #include From 698288d82202f5b55689db500033224f562481bc Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Sun, 2 Jan 2022 10:24:34 -0500 Subject: [PATCH 14/78] Added 12 hour set time --- src/displayapp/DisplayApp.cpp | 2 +- .../screens/settings/SettingSetTime.cpp | 75 +++++++++++++++++-- .../screens/settings/SettingSetTime.h | 11 ++- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index cc544fdb7c..1b77e87d73 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -417,7 +417,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingSetTime: - currentScreen = std::make_unique(this, dateTimeController); + currentScreen = std::make_unique(this, dateTimeController, settingsController); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingChimes: diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index 5351adebae..a432c758c4 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -4,6 +4,7 @@ #include #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" +#include "components/settings/Settings.h" using namespace Pinetime::Applications::Screens; @@ -22,9 +23,13 @@ namespace { } } -SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController) : - Screen(app), - dateTimeController {dateTimeController} { +SettingSetTime::SettingSetTime( + Pinetime::Applications::DisplayApp *app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController) + : Screen(app), + dateTimeController {dateTimeController}, + settingsController {settingsController} { lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Set current time"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); @@ -71,6 +76,24 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp *app, Pinetime lv_label_set_align(lblSeconds, LV_LABEL_ALIGN_CENTER); lv_obj_align(lblSeconds, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT); + lblampm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT - 40); + lv_label_set_text_fmt(lblampm, "%02c", ampmValue); + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) + lv_label_set_text(lblampm, " "); + else { + if (hoursValue > 11) + lv_label_set_text(lblampm, "PM"); + else + lv_label_set_text(lblampm, "AM"); + if (hoursValue > 12) + lv_label_set_text_fmt(lblHours, "%02d", hoursValue-12); + else if (hoursValue == 0) + lv_label_set_text_fmt(lblHours, "%02d", hoursValue+1); + } + btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr); btnHoursPlus->user_data = this; lv_obj_set_size(btnHoursPlus, 50, 40); @@ -111,21 +134,63 @@ SettingSetTime::~SettingSetTime() { lv_obj_clean(lv_scr_act()); } +int timeConvert(int time24H) { + switch (time24H) { + case 0: + return 12; + break; + case 1 ... 12: + return time24H; + break; + case 13 ... 23: + return time24H - 12; + break; + default: + return 99; + break; + } +} + void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { if (event != LV_EVENT_CLICKED) return; + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { + is24H = true; + } + else { + is24H = false; + } + if (object == btnHoursPlus) { hoursValue++; if (hoursValue > 23) hoursValue = 0; - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + if (!is24H) { + if (hoursValue < 12) + lv_label_set_text(lblampm, "AM"); + else + lv_label_set_text(lblampm, "PM"); + } + if (!is24H) + lv_label_set_text_fmt(lblHours, "%02d", timeConvert(hoursValue)); + else + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnHoursMinus) { hoursValue--; if (hoursValue < 0) hoursValue = 23; - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + if (!is24H) { + if (hoursValue < 12) + lv_label_set_text(lblampm, "AM"); + else + lv_label_set_text(lblampm, "PM"); + } + if (!is24H) + lv_label_set_text_fmt(lblHours, "%02d", timeConvert(hoursValue)); + else + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesPlus) { minutesValue++; diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index 8ba41eae45..31f7d0be6d 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -3,6 +3,7 @@ #include #include #include "components/datetime/DateTimeController.h" +#include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" namespace Pinetime { @@ -10,18 +11,24 @@ namespace Pinetime { namespace Screens { class SettingSetTime : public Screen{ public: - SettingSetTime(DisplayApp* app, Pinetime::Controllers::DateTime &dateTimeController); + SettingSetTime(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController); ~SettingSetTime() override; void HandleButtonPress(lv_obj_t *object, lv_event_t event); - + private: Controllers::DateTime& dateTimeController; + Controllers::Settings& settingsController; int hoursValue; int minutesValue; + char ampmValue[3]; + bool is24H; lv_obj_t * lblHours; lv_obj_t * lblMinutes; + lv_obj_t * lblampm; lv_obj_t * btnHoursPlus; lv_obj_t * btnHoursMinus; lv_obj_t * btnMinutesPlus; From 2bc338ceede540aabbb9d6054e14760c7f4fc95b Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Mon, 3 Jan 2022 18:13:47 -0500 Subject: [PATCH 15/78] Cleaned up redundant if statements, spacing Removed redundant if statements in hour button logic. Spacing is now in line with repo guidelines. --- .../screens/settings/SettingSetTime.cpp | 86 +++++++++---------- .../screens/settings/SettingSetTime.h | 4 +- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index a432c758c4..8d64dd92d6 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -24,9 +24,9 @@ namespace { } SettingSetTime::SettingSetTime( - Pinetime::Applications::DisplayApp *app, - Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController) + Pinetime::Applications::DisplayApp *app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController) : Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController} { @@ -82,16 +82,16 @@ SettingSetTime::SettingSetTime( lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT - 40); lv_label_set_text_fmt(lblampm, "%02c", ampmValue); if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) - lv_label_set_text(lblampm, " "); + lv_label_set_text(lblampm, " "); else { - if (hoursValue > 11) + if (hoursValue > 11) lv_label_set_text(lblampm, "PM"); else - lv_label_set_text(lblampm, "AM"); - if (hoursValue > 12) - lv_label_set_text_fmt(lblHours, "%02d", hoursValue-12); - else if (hoursValue == 0) - lv_label_set_text_fmt(lblHours, "%02d", hoursValue+1); + lv_label_set_text(lblampm, "AM"); + if (hoursValue > 12) + lv_label_set_text_fmt(lblHours, "%02d", hoursValue-12); + else if (hoursValue == 0) + lv_label_set_text_fmt(lblHours, "%02d", hoursValue+1); } btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr); @@ -135,20 +135,20 @@ SettingSetTime::~SettingSetTime() { } int timeConvert(int time24H) { - switch (time24H) { - case 0: - return 12; - break; - case 1 ... 12: - return time24H; - break; - case 13 ... 23: - return time24H - 12; - break; - default: - return 99; - break; - } + switch (time24H) { + case 0: + return 12; + break; + case 1 ... 12: + return time24H; + break; + case 13 ... 23: + return time24H - 12; + break; + default: + return 99; + break; + } } void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { @@ -156,41 +156,36 @@ void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { return; if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - is24H = true; + is24H = true; } else { - is24H = false; + is24H = false; } - if (object == btnHoursPlus) { hoursValue++; if (hoursValue > 23) hoursValue = 0; - if (!is24H) { - if (hoursValue < 12) - lv_label_set_text(lblampm, "AM"); - else - lv_label_set_text(lblampm, "PM"); - } - if (!is24H) + if (!is24H) { + if (hoursValue < 12) + lv_label_set_text(lblampm, "AM"); + else + lv_label_set_text(lblampm, "PM"); lv_label_set_text_fmt(lblHours, "%02d", timeConvert(hoursValue)); - else - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + } else + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnHoursMinus) { hoursValue--; if (hoursValue < 0) hoursValue = 23; - if (!is24H) { - if (hoursValue < 12) - lv_label_set_text(lblampm, "AM"); - else - lv_label_set_text(lblampm, "PM"); - } - if (!is24H) + if (!is24H) { + if (hoursValue < 12) + lv_label_set_text(lblampm, "AM"); + else + lv_label_set_text(lblampm, "PM"); lv_label_set_text_fmt(lblHours, "%02d", timeConvert(hoursValue)); - else - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + } else + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesPlus) { minutesValue++; @@ -217,3 +212,4 @@ void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); } } +} diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index 31f7d0be6d..74588ca371 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -12,8 +12,8 @@ namespace Pinetime { class SettingSetTime : public Screen{ public: SettingSetTime(DisplayApp* app, - Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController); + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController); ~SettingSetTime() override; void HandleButtonPress(lv_obj_t *object, lv_event_t event); From 18133999593574e48ecbf1284e669dc0d8f53011 Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Mon, 3 Jan 2022 18:22:42 -0500 Subject: [PATCH 16/78] Removed redundant brackets Also corrected orphaned bracket --- src/displayapp/screens/settings/SettingSetTime.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index 8d64dd92d6..7e4215d94b 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -155,12 +155,11 @@ void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { if (event != LV_EVENT_CLICKED) return; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) is24H = true; - } - else { + else is24H = false; - } + if (object == btnHoursPlus) { hoursValue++; if (hoursValue > 23) @@ -212,4 +211,3 @@ void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); } } -} From 5be2f57a78edd37bd8d844b4d56adc82f2d183dc Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Sun, 9 Jan 2022 10:39:04 -0500 Subject: [PATCH 17/78] Consolidated time conversion logic Consolidated 24 hour to 12 hour time conversion logic into function, addressed formatting issues, cleaned up code. --- .../screens/settings/SettingSetTime.cpp | 139 ++++++++++-------- .../screens/settings/SettingSetTime.h | 42 +++--- 2 files changed, 94 insertions(+), 87 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index 7e4215d94b..b68e540bbb 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" #include "components/settings/Settings.h" @@ -17,27 +18,31 @@ namespace { constexpr int16_t POS_Y_MINUS = 40; constexpr int16_t OFS_Y_COLON = -2; - void event_handler(lv_obj_t * obj, lv_event_t event) { - auto* screen = static_cast(obj->user_data); + void event_handler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); screen->HandleButtonPress(obj, event); } } -SettingSetTime::SettingSetTime( - Pinetime::Applications::DisplayApp *app, - Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController) - : Screen(app), - dateTimeController {dateTimeController}, - settingsController {settingsController} { - lv_obj_t * title = lv_label_create(lv_scr_act(), nullptr); +struct Time12H { + std::string ampm; + int hours; +}; + +Time12H timeConvert(int time24H); + +SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController) + : Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController} { + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Set current time"); 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_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); @@ -50,7 +55,7 @@ SettingSetTime::SettingSetTime( lv_obj_align(lblHours, lv_scr_act(), LV_ALIGN_CENTER, POS_X_HOURS, POS_Y_TEXT); lv_obj_set_auto_realign(lblHours, true); - lv_obj_t * lblColon1 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_t* lblColon1 = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(lblColon1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_static(lblColon1, ":"); lv_label_set_align(lblColon1, LV_LABEL_ALIGN_CENTER); @@ -64,13 +69,13 @@ SettingSetTime::SettingSetTime( lv_obj_align(lblMinutes, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MINUTES, POS_Y_TEXT); lv_obj_set_auto_realign(lblMinutes, true); - lv_obj_t * lblColon2 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_t* lblColon2 = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(lblColon2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_static(lblColon2, ":"); lv_label_set_align(lblColon2, LV_LABEL_ALIGN_CENTER); lv_obj_align(lblColon2, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_MINUTES + POS_X_SECONDS) / 2, POS_Y_TEXT + OFS_Y_COLON); - lv_obj_t * lblSeconds = lv_label_create(lv_scr_act(), nullptr); + lv_obj_t* lblSeconds = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(lblSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_static(lblSeconds, "00"); lv_label_set_align(lblSeconds, LV_LABEL_ALIGN_CENTER); @@ -78,21 +83,9 @@ SettingSetTime::SettingSetTime( lblampm = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_text_static(lblampm, " "); lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); - lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT - 40); - lv_label_set_text_fmt(lblampm, "%02c", ampmValue); - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) - lv_label_set_text(lblampm, " "); - else { - if (hoursValue > 11) - lv_label_set_text(lblampm, "PM"); - else - lv_label_set_text(lblampm, "AM"); - if (hoursValue > 12) - lv_label_set_text_fmt(lblHours, "%02d", hoursValue-12); - else if (hoursValue == 0) - lv_label_set_text_fmt(lblHours, "%02d", hoursValue+1); - } + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_PLUS); btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr); btnHoursPlus->user_data = this; @@ -128,74 +121,90 @@ SettingSetTime::SettingSetTime( lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set"); lv_obj_set_event_cb(btnSetTime, event_handler); + + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + struct Time12H convertedTime = timeConvert(hoursValue); + if (hoursValue < 12) { + lv_label_set_text_static(lblampm, "AM"); + } else { + lv_label_set_text_static(lblampm, "PM"); + } + lv_label_set_text_fmt(lblHours, "%02d", convertedTime.hours); + } } SettingSetTime::~SettingSetTime() { lv_obj_clean(lv_scr_act()); } -int timeConvert(int time24H) { - switch (time24H) { - case 0: - return 12; - break; - case 1 ... 12: - return time24H; - break; - case 13 ... 23: - return time24H - 12; - break; - default: - return 99; - break; - } +Time12H timeConvert(int time24H) { + struct Time12H time12H; + switch (time24H) { + case 0: + time12H.hours = 12; + time12H.ampm = "AM"; + break; + case 1 ... 11: + time12H.hours = time24H; + time12H.ampm = "AM"; + break; + case 12: + time12H.hours = 12; + time12H.ampm = "PM"; + break; + case 13 ... 23: + time12H.hours = time24H - 12; + time12H.ampm = "PM"; + break; + } + return time12H; } -void SettingSetTime::HandleButtonPress(lv_obj_t *object, lv_event_t event) { +void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { + bool is24H; if (event != LV_EVENT_CLICKED) return; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) - is24H = true; - else - is24H = false; + is24H = (settingsController.GetClockType() == Controllers::Settings::ClockType::H24); if (object == btnHoursPlus) { hoursValue++; - if (hoursValue > 23) + if (hoursValue > 23) { hoursValue = 0; + } + struct Time12H convertedTime = timeConvert(hoursValue); if (!is24H) { - if (hoursValue < 12) - lv_label_set_text(lblampm, "AM"); - else - lv_label_set_text(lblampm, "PM"); - lv_label_set_text_fmt(lblHours, "%02d", timeConvert(hoursValue)); - } else + lv_label_set_text_static(lblampm, convertedTime.ampm.c_str()); + lv_label_set_text_fmt(lblHours, "%02d", convertedTime.hours); + } else { lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + } lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnHoursMinus) { hoursValue--; - if (hoursValue < 0) + if (hoursValue < 0) { hoursValue = 23; + } + struct Time12H convertedTime = timeConvert(hoursValue); if (!is24H) { - if (hoursValue < 12) - lv_label_set_text(lblampm, "AM"); - else - lv_label_set_text(lblampm, "PM"); - lv_label_set_text_fmt(lblHours, "%02d", timeConvert(hoursValue)); - } else + lv_label_set_text_static(lblampm, convertedTime.ampm.c_str()); + lv_label_set_text_fmt(lblHours, "%02d", convertedTime.hours); + } else { lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + } lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesPlus) { minutesValue++; - if (minutesValue > 59) + if (minutesValue > 59) { minutesValue = 0; + } lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesMinus) { minutesValue--; - if (minutesValue < 0) + if (minutesValue < 0) { minutesValue = 59; + } lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnSetTime) { diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index 74588ca371..eb0423f2a6 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -9,31 +9,29 @@ namespace Pinetime { namespace Applications { namespace Screens { - class SettingSetTime : public Screen{ - public: - SettingSetTime(DisplayApp* app, - Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController); - ~SettingSetTime() override; + class SettingSetTime : public Screen { + public: + SettingSetTime(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController); + ~SettingSetTime() override; - void HandleButtonPress(lv_obj_t *object, lv_event_t event); + void HandleButtonPress(lv_obj_t* object, lv_event_t event); - private: - Controllers::DateTime& dateTimeController; - Controllers::Settings& settingsController; + private: + Controllers::DateTime& dateTimeController; + Controllers::Settings& settingsController; - int hoursValue; - int minutesValue; - char ampmValue[3]; - bool is24H; - lv_obj_t * lblHours; - lv_obj_t * lblMinutes; - lv_obj_t * lblampm; - lv_obj_t * btnHoursPlus; - lv_obj_t * btnHoursMinus; - lv_obj_t * btnMinutesPlus; - lv_obj_t * btnMinutesMinus; - lv_obj_t * btnSetTime; + int hoursValue; + int minutesValue; + lv_obj_t* lblHours; + lv_obj_t* lblMinutes; + lv_obj_t* lblampm; + lv_obj_t* btnHoursPlus; + lv_obj_t* btnHoursMinus; + lv_obj_t* btnMinutesPlus; + lv_obj_t* btnMinutesMinus; + lv_obj_t* btnSetTime; }; } } From c8d998e82c691a79ddfd19b7a175dfba2d958ffa Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Mon, 10 Jan 2022 10:16:38 -0500 Subject: [PATCH 18/78] Consolidated label changes, optimizations Consolidated 12 hour label changes to function. Removed use of strings, struct. --- .../screens/settings/SettingSetTime.cpp | 51 ++++++------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index b68e540bbb..7540a4db04 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" #include "components/settings/Settings.h" @@ -24,12 +23,7 @@ namespace { } } -struct Time12H { - std::string ampm; - int hours; -}; - -Time12H timeConvert(int time24H); +void set12HourLabels(int time24H, lv_obj_t* lblampm, lv_obj_t* lblHours); SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController, @@ -123,13 +117,7 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, lv_obj_set_event_cb(btnSetTime, event_handler); if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - struct Time12H convertedTime = timeConvert(hoursValue); - if (hoursValue < 12) { - lv_label_set_text_static(lblampm, "AM"); - } else { - lv_label_set_text_static(lblampm, "PM"); - } - lv_label_set_text_fmt(lblHours, "%02d", convertedTime.hours); + set12HourLabels(hoursValue, lblampm, lblHours); } } @@ -137,45 +125,38 @@ SettingSetTime::~SettingSetTime() { lv_obj_clean(lv_scr_act()); } -Time12H timeConvert(int time24H) { - struct Time12H time12H; +void set12HourLabels(int time24H, lv_obj_t* lblampm, lv_obj_t* lblHours) { switch (time24H) { case 0: - time12H.hours = 12; - time12H.ampm = "AM"; + lv_label_set_text_fmt(lblHours, "%02d", 12); + lv_label_set_text_static(lblampm, "AM"); break; case 1 ... 11: - time12H.hours = time24H; - time12H.ampm = "AM"; + lv_label_set_text_fmt(lblHours, "%02d", time24H); + lv_label_set_text_static(lblampm, "AM"); break; case 12: - time12H.hours = 12; - time12H.ampm = "PM"; + lv_label_set_text_fmt(lblHours, "%02d", 12); + lv_label_set_text_static(lblampm, "PM"); break; case 13 ... 23: - time12H.hours = time24H - 12; - time12H.ampm = "PM"; + lv_label_set_text_fmt(lblHours, "%02d", time24H - 12); + lv_label_set_text_static(lblampm, "PM"); break; } - return time12H; } void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { - bool is24H; if (event != LV_EVENT_CLICKED) return; - is24H = (settingsController.GetClockType() == Controllers::Settings::ClockType::H24); - if (object == btnHoursPlus) { hoursValue++; if (hoursValue > 23) { hoursValue = 0; } - struct Time12H convertedTime = timeConvert(hoursValue); - if (!is24H) { - lv_label_set_text_static(lblampm, convertedTime.ampm.c_str()); - lv_label_set_text_fmt(lblHours, "%02d", convertedTime.hours); + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + set12HourLabels(hoursValue, lblampm, lblHours); } else { lv_label_set_text_fmt(lblHours, "%02d", hoursValue); } @@ -185,10 +166,8 @@ void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { if (hoursValue < 0) { hoursValue = 23; } - struct Time12H convertedTime = timeConvert(hoursValue); - if (!is24H) { - lv_label_set_text_static(lblampm, convertedTime.ampm.c_str()); - lv_label_set_text_fmt(lblHours, "%02d", convertedTime.hours); + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + set12HourLabels(hoursValue, lblampm, lblHours); } else { lv_label_set_text_fmt(lblHours, "%02d", hoursValue); } From d86f81b9ad68dd6baab434f6adcbf0e728caf3c6 Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Tue, 11 Jan 2022 10:24:17 -0500 Subject: [PATCH 19/78] Changed setHourLabels function to handle 24H too Changed setHourLabels function to handle 24 hour time labeling, changed to private --- .../screens/settings/SettingSetTime.cpp | 39 ++----------------- .../screens/settings/SettingSetTime.h | 25 ++++++++++++ 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index 7540a4db04..b6d64dd365 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -23,8 +23,6 @@ namespace { } } -void set12HourLabels(int time24H, lv_obj_t* lblampm, lv_obj_t* lblHours); - SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController, Pinetime::Controllers::Settings& settingsController) @@ -116,36 +114,13 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set"); lv_obj_set_event_cb(btnSetTime, event_handler); - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - set12HourLabels(hoursValue, lblampm, lblHours); - } + setHourLabels(hoursValue); } SettingSetTime::~SettingSetTime() { lv_obj_clean(lv_scr_act()); } -void set12HourLabels(int time24H, lv_obj_t* lblampm, lv_obj_t* lblHours) { - switch (time24H) { - case 0: - lv_label_set_text_fmt(lblHours, "%02d", 12); - lv_label_set_text_static(lblampm, "AM"); - break; - case 1 ... 11: - lv_label_set_text_fmt(lblHours, "%02d", time24H); - lv_label_set_text_static(lblampm, "AM"); - break; - case 12: - lv_label_set_text_fmt(lblHours, "%02d", 12); - lv_label_set_text_static(lblampm, "PM"); - break; - case 13 ... 23: - lv_label_set_text_fmt(lblHours, "%02d", time24H - 12); - lv_label_set_text_static(lblampm, "PM"); - break; - } -} - void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { if (event != LV_EVENT_CLICKED) return; @@ -155,22 +130,14 @@ void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { if (hoursValue > 23) { hoursValue = 0; } - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - set12HourLabels(hoursValue, lblampm, lblHours); - } else { - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); - } + setHourLabels(hoursValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnHoursMinus) { hoursValue--; if (hoursValue < 0) { hoursValue = 23; } - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - set12HourLabels(hoursValue, lblampm, lblHours); - } else { - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); - } + setHourLabels(hoursValue); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesPlus) { minutesValue++; diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index eb0423f2a6..cc4e4692bb 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -32,6 +32,31 @@ namespace Pinetime { lv_obj_t* btnMinutesPlus; lv_obj_t* btnMinutesMinus; lv_obj_t* btnSetTime; + + void setHourLabels(int time24H) { + switch (time24H) { + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + case 0: + lv_label_set_text_static(lblHours, "12"); + lv_label_set_text_static(lblampm, "AM"); + break; + case 1 ... 11: + lv_label_set_text_fmt(lblHours, "%02d", time24H); + lv_label_set_text_static(lblampm, "AM"); + break; + case 12: + lv_label_set_text_static(lblHours, "12"); + lv_label_set_text_static(lblampm, "PM"); + break; + case 13 ... 23: + lv_label_set_text_fmt(lblHours, "%02d", time24H - 12); + lv_label_set_text_static(lblampm, "PM"); + break; + } else { + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + } + } + } }; } } From 02e94acf185aa271e4b3773251efc3108c555fe2 Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Tue, 11 Jan 2022 16:23:49 -0500 Subject: [PATCH 20/78] Corrected code formatting Corrected formatting and removed unnecessary variable time24H --- .../screens/settings/SettingSetTime.cpp | 31 +++++++++++++++++-- .../screens/settings/SettingSetTime.h | 27 ++-------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index b6d64dd365..fd0a8a3afc 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -114,13 +114,38 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set"); lv_obj_set_event_cb(btnSetTime, event_handler); - setHourLabels(hoursValue); + setHourLabels(); } SettingSetTime::~SettingSetTime() { lv_obj_clean(lv_scr_act()); } +void SettingSetTime::setHourLabels() { + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + switch (hoursValue) { + case 0: + lv_label_set_text_static(lblHours, "12"); + lv_label_set_text_static(lblampm, "AM"); + break; + case 1 ... 11: + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + lv_label_set_text_static(lblampm, "AM"); + break; + case 12: + lv_label_set_text_static(lblHours, "12"); + lv_label_set_text_static(lblampm, "PM"); + break; + case 13 ... 23: + lv_label_set_text_fmt(lblHours, "%02d", hoursValue - 12); + lv_label_set_text_static(lblampm, "PM"); + break; + } + } else { + lv_label_set_text_fmt(lblHours, "%02d", hoursValue); + } +} + void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { if (event != LV_EVENT_CLICKED) return; @@ -130,14 +155,14 @@ void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { if (hoursValue > 23) { hoursValue = 0; } - setHourLabels(hoursValue); + setHourLabels(); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnHoursMinus) { hoursValue--; if (hoursValue < 0) { hoursValue = 23; } - setHourLabels(hoursValue); + setHourLabels(); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesPlus) { minutesValue++; diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index cc4e4692bb..285156864c 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -22,6 +22,8 @@ namespace Pinetime { Controllers::DateTime& dateTimeController; Controllers::Settings& settingsController; + void setHourLabels(); + int hoursValue; int minutesValue; lv_obj_t* lblHours; @@ -32,31 +34,6 @@ namespace Pinetime { lv_obj_t* btnMinutesPlus; lv_obj_t* btnMinutesMinus; lv_obj_t* btnSetTime; - - void setHourLabels(int time24H) { - switch (time24H) { - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - case 0: - lv_label_set_text_static(lblHours, "12"); - lv_label_set_text_static(lblampm, "AM"); - break; - case 1 ... 11: - lv_label_set_text_fmt(lblHours, "%02d", time24H); - lv_label_set_text_static(lblampm, "AM"); - break; - case 12: - lv_label_set_text_static(lblHours, "12"); - lv_label_set_text_static(lblampm, "PM"); - break; - case 13 ... 23: - lv_label_set_text_fmt(lblHours, "%02d", time24H - 12); - lv_label_set_text_static(lblampm, "PM"); - break; - } else { - lv_label_set_text_fmt(lblHours, "%02d", hoursValue); - } - } - } }; } } From ae0724c28c33cf99886aae7df1997ed5a23f0684 Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Tue, 11 Jan 2022 16:25:26 -0500 Subject: [PATCH 21/78] Corrected capitalization --- src/displayapp/screens/settings/SettingSetTime.cpp | 8 ++++---- src/displayapp/screens/settings/SettingSetTime.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index fd0a8a3afc..037611f303 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -114,14 +114,14 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set"); lv_obj_set_event_cb(btnSetTime, event_handler); - setHourLabels(); + SetHourLabels(); } SettingSetTime::~SettingSetTime() { lv_obj_clean(lv_scr_act()); } -void SettingSetTime::setHourLabels() { +void SettingSetTime::SetHourLabels() { if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { switch (hoursValue) { case 0: @@ -155,14 +155,14 @@ void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) { if (hoursValue > 23) { hoursValue = 0; } - setHourLabels(); + SetHourLabels(); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnHoursMinus) { hoursValue--; if (hoursValue < 0) { hoursValue = 23; } - setHourLabels(); + SetHourLabels(); lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); } else if (object == btnMinutesPlus) { minutesValue++; diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index 285156864c..d02c332e64 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -22,7 +22,7 @@ namespace Pinetime { Controllers::DateTime& dateTimeController; Controllers::Settings& settingsController; - void setHourLabels(); + void SetHourLabels(); int hoursValue; int minutesValue; From 2daa5dcbeeecc0d6940906dadc42df1bd10b9b7e Mon Sep 17 00:00:00 2001 From: Eli Weiss Date: Sun, 16 Jan 2022 09:40:23 -0500 Subject: [PATCH 22/78] Added alarm 12 hour interface --- src/displayapp/DisplayApp.cpp | 4 ++-- src/displayapp/screens/Alarm.cpp | 36 +++++++++++++++++++++++++++++--- src/displayapp/screens/Alarm.h | 7 ++++--- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 1b77e87d73..672bcb3457 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -379,7 +379,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentScreen = std::make_unique(this, timerController); break; case Apps::Alarm: - currentScreen = std::make_unique(this, alarmController); + currentScreen = std::make_unique(this, alarmController, settingsController); break; // Settings @@ -425,7 +425,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingShakeThreshold: - currentScreen = std::make_unique(this, settingsController,motionController,*systemTask); + currentScreen = std::make_unique(this, settingsController, motionController, *systemTask); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::BatteryInfo: diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index 537ac0e066..b8eaa6d59c 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -27,8 +27,8 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { screen->OnButtonEvent(obj, event); } -Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController) - : Screen(app), running {true}, alarmController {alarmController} { +Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pinetime::Controllers::Settings& settingsController) + : Screen(app), running {true}, alarmController {alarmController}, settingsController {settingsController} { time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); @@ -40,6 +40,13 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController) lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25); + lblampm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_set_style_local_text_color(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_label_set_text_static(lblampm, " "); + lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + btnHoursUp = lv_btn_create(lv_scr_act(), nullptr); btnHoursUp->user_data = this; lv_obj_set_event_cb(btnHoursUp, btnEventHandler); @@ -95,6 +102,8 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController) lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85); txtInfo = lv_label_create(btnInfo, nullptr); lv_label_set_text_static(txtInfo, "i"); + + UpdateAlarmTime(); } Alarm::~Alarm() { @@ -180,7 +189,28 @@ bool Alarm::OnButtonPushed() { } void Alarm::UpdateAlarmTime() { - lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes); + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + switch (alarmHours) { + case 0: + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_text_fmt(time, "%02d:%02d", 12, alarmMinutes); + break; + case 1 ... 11: + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes); + break; + case 12: + lv_label_set_text_static(lblampm, "PM"); + lv_label_set_text_fmt(time, "%02d:%02d", 12, alarmMinutes); + break; + case 13 ... 23: + lv_label_set_text_static(lblampm, "PM"); + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours - 12, alarmMinutes); + break; + } + } else { + lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes); + } alarmController.SetAlarmTime(alarmHours, alarmMinutes); } diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h index 4b301ce194..d45fb96ce5 100644 --- a/src/displayapp/screens/Alarm.h +++ b/src/displayapp/screens/Alarm.h @@ -27,7 +27,7 @@ namespace Pinetime { namespace Screens { class Alarm : public Screen { public: - Alarm(DisplayApp* app, Controllers::AlarmController& alarmController); + Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pinetime::Controllers::Settings& settingsController); ~Alarm() override; void SetAlerting(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); @@ -38,9 +38,10 @@ namespace Pinetime { uint8_t alarmHours; uint8_t alarmMinutes; Controllers::AlarmController& alarmController; + Controllers::Settings& settingsController; - lv_obj_t *time, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown, - *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo; + lv_obj_t *time, *lblampm, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, + *txtMinDown, *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo; lv_obj_t* txtMessage = nullptr; lv_obj_t* btnMessage = nullptr; From 1ac1d5aa5a7023e63c03327a5233dd885d4e9c00 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Wed, 26 Jan 2022 15:18:54 +0200 Subject: [PATCH 23/78] Add issue links --- .github/ISSUE_TEMPLATE/config.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..e5a555fd2a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: PineTime community chat (Matrix) + url: https://app.element.io/#/room/#pinetime:matrix.org + about: Please ask questions about PineTime here. + - name: PineTime developers chat (Matrix) + url: https://app.element.io/#/room/#pinetime-dev:matrix.org + about: Please ask questions about PineTime development here. From a9b77ae0d4bb450c42a17d1610225b7ee83edfe5 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Wed, 2 Feb 2022 13:57:30 +0200 Subject: [PATCH 24/78] Alarm: Change checkable button for a switch --- doc/ui_guidelines.md | 1 + src/displayapp/lv_pinetime_theme.c | 7 ++-- src/displayapp/lv_pinetime_theme.h | 2 +- src/displayapp/screens/Alarm.cpp | 67 +++++++++++++++++++----------- src/displayapp/screens/Alarm.h | 8 ++-- 5 files changed, 52 insertions(+), 33 deletions(-) diff --git a/doc/ui_guidelines.md b/doc/ui_guidelines.md index 0cbd39f587..296497af7a 100644 --- a/doc/ui_guidelines.md +++ b/doc/ui_guidelines.md @@ -9,5 +9,6 @@ - Top bar takes at least 20px + padding - Top bar right icons move 8px to the left when using a page indicator - A black background helps to hide the screen border, allowing the UI to look less cramped when utilizing the entire display area. +- A switch should be twice as wide as it is tall. ![example layouts](./ui/example.png) diff --git a/src/displayapp/lv_pinetime_theme.c b/src/displayapp/lv_pinetime_theme.c index b74b2fd7ef..deb66a97f9 100644 --- a/src/displayapp/lv_pinetime_theme.c +++ b/src/displayapp/lv_pinetime_theme.c @@ -199,17 +199,16 @@ static void basic_init(void) { style_init_reset(&style_sw_bg); lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_LIGHT_GRAY); + lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE); lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_value_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE); style_init_reset(&style_sw_indic); lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_PINETIME_GREEN); + lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_COLOR_GREEN); style_init_reset(&style_sw_knob); lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_PINETIME_WHITE); + lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, 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); diff --git a/src/displayapp/lv_pinetime_theme.h b/src/displayapp/lv_pinetime_theme.h index f914516d3d..714c4242b5 100644 --- a/src/displayapp/lv_pinetime_theme.h +++ b/src/displayapp/lv_pinetime_theme.h @@ -23,7 +23,7 @@ extern "C" { #define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe) #define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a) #define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4) -#define LV_PINETIME_BLUE lv_color_hex(0x2f3243) // 006fb6 +#define LV_PINETIME_BLUE lv_color_hex(0x2f3540) #define LV_PINETIME_GREEN lv_color_hex(0x4cb242) #define LV_PINETIME_RED lv_color_hex(0xd51732) diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index b8eaa6d59c..32f68b8419 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -28,7 +28,7 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { } Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pinetime::Controllers::Settings& settingsController) - : Screen(app), running {true}, alarmController {alarmController}, settingsController {settingsController} { + : Screen(app), alarmController {alarmController}, settingsController {settingsController} { time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); @@ -79,13 +79,15 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pin txtMinDown = lv_label_create(btnMinutesDown, nullptr); lv_label_set_text_static(txtMinDown, "-"); - btnEnable = lv_btn_create(lv_scr_act(), nullptr); - btnEnable->user_data = this; - lv_obj_set_event_cb(btnEnable, btnEventHandler); - lv_obj_set_size(btnEnable, 115, 50); - lv_obj_align(btnEnable, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - txtEnable = lv_label_create(btnEnable, nullptr); - SetEnableButtonState(); + btnStop = lv_btn_create(lv_scr_act(), nullptr); + btnStop->user_data = this; + lv_obj_set_event_cb(btnStop, btnEventHandler); + lv_obj_set_size(btnStop, 120, 50); + lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + txtStop = lv_label_create(btnStop, nullptr); + lv_label_set_text_static(txtStop, Symbols::stop); + lv_obj_set_hidden(btnStop, true); btnRecur = lv_btn_create(lv_scr_act(), nullptr); btnRecur->user_data = this; @@ -103,6 +105,13 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pin txtInfo = lv_label_create(btnInfo, nullptr); lv_label_set_text_static(txtInfo, "i"); + enableSwitch = lv_switch_create(lv_scr_act(), nullptr); + enableSwitch->user_data = this; + lv_obj_set_event_cb(enableSwitch, btnEventHandler); + lv_obj_set_size(enableSwitch, 100, 50); + // Align to the center of 115px from edge + lv_obj_align(enableSwitch, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 7, 0); + UpdateAlarmTime(); } @@ -113,15 +122,12 @@ Alarm::~Alarm() { void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { using Pinetime::Controllers::AlarmController; if (event == LV_EVENT_CLICKED) { - if (obj == btnEnable) { + if (obj == btnStop) { if (alarmController.State() == AlarmController::AlarmState::Alerting) { alarmController.StopAlerting(); - } else if (alarmController.State() == AlarmController::AlarmState::Set) { - alarmController.DisableAlarm(); - } else { - alarmController.ScheduleAlarm(); } - SetEnableButtonState(); + SetSwitchState(LV_ANIM_OFF); + StopAlerting(); return; } if (obj == btnInfo) { @@ -132,11 +138,19 @@ void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { HideInfo(); return; } + if (obj == enableSwitch) { + if (lv_switch_get_state(enableSwitch)) { + alarmController.ScheduleAlarm(); + } else { + alarmController.DisableAlarm(); + } + return; + } // If any other button was pressed, disable the alarm // this is to make it clear that the alarm won't be set until it is turned back on if (alarmController.State() == AlarmController::AlarmState::Set) { alarmController.DisableAlarm(); - SetEnableButtonState(); + lv_switch_off(enableSwitch, LV_ANIM_ON); } if (obj == btnMinutesUp) { if (alarmMinutes >= 59) { @@ -215,22 +229,27 @@ void Alarm::UpdateAlarmTime() { } void Alarm::SetAlerting() { - SetEnableButtonState(); + lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnRecur, true); + lv_obj_set_hidden(btnStop, false); } -void Alarm::SetEnableButtonState() { +void Alarm::StopAlerting() { + lv_obj_set_hidden(enableSwitch, false); + lv_obj_set_hidden(btnRecur, false); + lv_obj_set_hidden(btnStop, true); +} + +void Alarm::SetSwitchState(lv_anim_enable_t anim) { switch (alarmController.State()) { case AlarmController::AlarmState::Set: - lv_label_set_text(txtEnable, "ON"); - lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + lv_switch_on(enableSwitch, anim); break; case AlarmController::AlarmState::Not_Set: - lv_label_set_text(txtEnable, "OFF"); - lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_switch_off(enableSwitch, anim); + break; + default: break; - case AlarmController::AlarmState::Alerting: - lv_label_set_text(txtEnable, Symbols::stop); - lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } } diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h index d45fb96ce5..a7f352325e 100644 --- a/src/displayapp/screens/Alarm.h +++ b/src/displayapp/screens/Alarm.h @@ -34,21 +34,21 @@ namespace Pinetime { bool OnButtonPushed() override; private: - bool running; uint8_t alarmHours; uint8_t alarmMinutes; Controllers::AlarmController& alarmController; Controllers::Settings& settingsController; - lv_obj_t *time, *lblampm, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, - *txtMinDown, *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo; + lv_obj_t *time, *lblampm, *btnStop, *txtStop, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, + *txtMinDown, *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo, *enableSwitch; lv_obj_t* txtMessage = nullptr; lv_obj_t* btnMessage = nullptr; enum class EnableButtonState { On, Off, Alerting }; - void SetEnableButtonState(); void SetRecurButtonState(); + void SetSwitchState(lv_anim_enable_t anim); void SetAlarm(); + void StopAlerting(); void ShowInfo(); void HideInfo(); void ToggleRecurrence(); From 0930a79041f7d650b1e31e31cd659e271f7b027b Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Wed, 2 Feb 2022 16:22:44 +0200 Subject: [PATCH 25/78] Alarm: Fix missing stop button. Revert alert layout --- src/displayapp/screens/Alarm.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index 32f68b8419..06fb92fedc 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -82,8 +82,8 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pin btnStop = lv_btn_create(lv_scr_act(), nullptr); btnStop->user_data = this; lv_obj_set_event_cb(btnStop, btnEventHandler); - lv_obj_set_size(btnStop, 120, 50); - lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_set_size(btnStop, 115, 50); + lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); txtStop = lv_label_create(btnStop, nullptr); lv_label_set_text_static(txtStop, Symbols::stop); @@ -113,6 +113,10 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pin lv_obj_align(enableSwitch, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 7, 0); UpdateAlarmTime(); + + if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) { + SetAlerting(); + } } Alarm::~Alarm() { @@ -230,13 +234,11 @@ void Alarm::UpdateAlarmTime() { void Alarm::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); - lv_obj_set_hidden(btnRecur, true); lv_obj_set_hidden(btnStop, false); } void Alarm::StopAlerting() { lv_obj_set_hidden(enableSwitch, false); - lv_obj_set_hidden(btnRecur, false); lv_obj_set_hidden(btnStop, true); } From 76f63ed76a2c379b0ea192573cddb36f2bf683d4 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Wed, 2 Feb 2022 20:59:06 +0200 Subject: [PATCH 26/78] Fix switch default state --- src/displayapp/screens/Alarm.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index 06fb92fedc..a2f534df57 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -116,6 +116,8 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pin if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) { SetAlerting(); + } else { + SetSwitchState(LV_ANIM_OFF); } } From 32fe7b660c59cda789a16f30e1371b087fdab6a0 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Thu, 3 Feb 2022 12:36:45 +0200 Subject: [PATCH 27/78] Make switch disabled state slightly dimmer --- src/displayapp/lv_pinetime_theme.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/displayapp/lv_pinetime_theme.c b/src/displayapp/lv_pinetime_theme.c index deb66a97f9..4fce5d656b 100644 --- a/src/displayapp/lv_pinetime_theme.c +++ b/src/displayapp/lv_pinetime_theme.c @@ -208,7 +208,8 @@ static void basic_init(void) { style_init_reset(&style_sw_knob); lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); + 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); From 5938b4b208e5684c13716fce16c3982182fd40f7 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 29 Jan 2022 21:46:31 +0100 Subject: [PATCH 28/78] SystemTask: fix static cast missing brackets syntax The static_cast syntax requires brackets around the input variable. The implementation worked because the used input are defines, which add the missing brackets like the following: ```cpp #define GPIO_PIN_CNF_SENSE_Low (3UL) ``` --- src/systemtask/SystemTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 241b29bf31..e71ebc1711 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -197,13 +197,13 @@ void SystemTask::Work() { // Touchscreen nrf_gpio_cfg_sense_input(PinMap::Cst816sIrq, static_cast(GPIO_PIN_CNF_PULL_Pullup), - static_cast GPIO_PIN_CNF_SENSE_Low); + static_cast(GPIO_PIN_CNF_SENSE_Low)); pinConfig.skip_gpio_setup = true; pinConfig.hi_accuracy = false; pinConfig.is_watcher = false; pinConfig.sense = static_cast(NRF_GPIOTE_POLARITY_HITOLO); - pinConfig.pull = static_cast GPIO_PIN_CNF_PULL_Pullup; + pinConfig.pull = static_cast(GPIO_PIN_CNF_PULL_Pullup); nrfx_gpiote_in_init(PinMap::Cst816sIrq, &pinConfig, nrfx_gpiote_evt_handler); From d967efa19710f85cee846c59adbbe07d2a2189dc Mon Sep 17 00:00:00 2001 From: Zorvalt Date: Sun, 19 Dec 2021 17:10:50 +0100 Subject: [PATCH 29/78] Fix biased BLE pass key generation --- src/components/ble/NimbleController.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index d8510bd36c..00a394fe3d 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -278,7 +278,28 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { if (event->passkey.params.action == BLE_SM_IOACT_DISP) { struct ble_sm_io pkey = {0}; pkey.action = event->passkey.params.action; - pkey.passkey = ble_ll_rand() % 1000000; + + /* + * Passkey is a 6 digits code (1'000'000 possibilities). + * It is important every possible value has an equal probability + * of getting generated. Simply applying a modulo creates a bias + * since 2^32 is not a multiple of 1'000'000. + * To prevent that, we can reject values greater than 999'999. + * + * Rejecting values would happen a lot since 2^32-1 is way greater + * than 1'000'000. An optimisation is to use a multiple of 1'000'000. + * The greatest multiple of 1'000'000 lesser than 2^32-1 is + * 4'294'000'000. + * + * Great explanation at: + * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/ + */ + uint32_t passkey_rand; + do { + passkey_rand = ble_ll_rand(); + } while (passkey_rand > 4293999999); + pkey.passkey = passkey_rand % 1000000; + bleController.SetPairingKey(pkey.passkey); systemTask.PushMessage(Pinetime::System::Messages::OnPairing); ble_sm_inject_io(event->passkey.conn_handle, &pkey); From 4f649a85448fc79b55202d9db0e8f4c8828975e3 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Tue, 18 Jan 2022 19:08:03 +0200 Subject: [PATCH 30/78] Improved alarm alert handling --- src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/screens/Alarm.cpp | 39 ++++++++++++++++++++++++++------ src/displayapp/screens/Alarm.h | 10 ++++++-- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 672bcb3457..495969b3eb 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -379,7 +379,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentScreen = std::make_unique(this, timerController); break; case Apps::Alarm: - currentScreen = std::make_unique(this, alarmController, settingsController); + currentScreen = std::make_unique(this, alarmController, settingsController, *systemTask); break; // Settings diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index a2f534df57..879e50d858 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -23,12 +23,20 @@ using namespace Pinetime::Applications::Screens; using Pinetime::Controllers::AlarmController; static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { - Alarm* screen = static_cast(obj->user_data); + auto* screen = static_cast(obj->user_data); screen->OnButtonEvent(obj, event); } -Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pinetime::Controllers::Settings& settingsController) - : Screen(app), alarmController {alarmController}, settingsController {settingsController} { +static void StopAlarmTaskCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->StopAlerting(); +} + +Alarm::Alarm(DisplayApp* app, + Controllers::AlarmController& alarmController, + Pinetime::Controllers::Settings& settingsController, + System::SystemTask& systemTask) + : Screen(app), alarmController {alarmController}, settingsController {settingsController}, systemTask {systemTask} { time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); @@ -122,6 +130,9 @@ Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pin } Alarm::~Alarm() { + if (alarmController.State() == AlarmController::AlarmState::Alerting) { + StopAlerting(); + } lv_obj_clean(lv_scr_act()); } @@ -129,10 +140,6 @@ void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { using Pinetime::Controllers::AlarmController; if (event == LV_EVENT_CLICKED) { if (obj == btnStop) { - if (alarmController.State() == AlarmController::AlarmState::Alerting) { - alarmController.StopAlerting(); - } - SetSwitchState(LV_ANIM_OFF); StopAlerting(); return; } @@ -205,9 +212,18 @@ bool Alarm::OnButtonPushed() { HideInfo(); return true; } + if (alarmController.State() == AlarmController::AlarmState::Alerting) { + StopAlerting(); + return true; + } return false; } +bool Alarm::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + // Don't allow closing the screen by swiping while the alarm is alerting + return alarmController.State() == AlarmController::AlarmState::Alerting && event == TouchEvents::SwipeDown; +} + void Alarm::UpdateAlarmTime() { if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { switch (alarmHours) { @@ -237,9 +253,18 @@ void Alarm::UpdateAlarmTime() { void Alarm::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); + taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); + systemTask.PushMessage(System::Messages::DisableSleeping); } void Alarm::StopAlerting() { + alarmController.StopAlerting(); + SetSwitchState(LV_ANIM_OFF); + if (taskStopAlarm != nullptr) { + lv_task_del(taskStopAlarm); + taskStopAlarm = nullptr; + } + systemTask.PushMessage(System::Messages::EnableSleeping); lv_obj_set_hidden(enableSwitch, false); lv_obj_set_hidden(btnStop, true); } diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h index a7f352325e..f74dd68efa 100644 --- a/src/displayapp/screens/Alarm.h +++ b/src/displayapp/screens/Alarm.h @@ -27,28 +27,34 @@ namespace Pinetime { namespace Screens { class Alarm : public Screen { public: - Alarm(DisplayApp* app, Controllers::AlarmController& alarmController, Pinetime::Controllers::Settings& settingsController); + Alarm(DisplayApp* app, + Controllers::AlarmController& alarmController, + Pinetime::Controllers::Settings& settingsController, + System::SystemTask& systemTask); ~Alarm() override; void SetAlerting(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); bool OnButtonPushed() override; + bool OnTouchEvent(TouchEvents event) override; + void StopAlerting(); private: uint8_t alarmHours; uint8_t alarmMinutes; Controllers::AlarmController& alarmController; Controllers::Settings& settingsController; + System::SystemTask& systemTask; lv_obj_t *time, *lblampm, *btnStop, *txtStop, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown, *txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo, *enableSwitch; lv_obj_t* txtMessage = nullptr; lv_obj_t* btnMessage = nullptr; + lv_task_t* taskStopAlarm = nullptr; enum class EnableButtonState { On, Off, Alerting }; void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetAlarm(); - void StopAlerting(); void ShowInfo(); void HideInfo(); void ToggleRecurrence(); From d5b78ecd6690180f4f0891780dc7fe7a8ef91212 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 29 Jan 2022 22:08:52 +0100 Subject: [PATCH 31/78] SystemTask: remove unused ble includes Remove unused includes. The firmware still compiles fine without the includes. --- src/systemtask/SystemTask.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index e71ebc1711..6460cd4b5b 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -1,13 +1,4 @@ #include "systemtask/SystemTask.h" -#define min // workaround: nimble's min/max macros conflict with libstdc++ -#define max -#include -#include -#include -#include -#include -#undef max -#undef min #include #include #include From 04eca81a956ad84a5604096515da1ac148fe8921 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 29 Jan 2022 23:34:09 +0100 Subject: [PATCH 32/78] Notifications: use motorController object instead of class function We get the motoroController object, so store and use it. --- src/displayapp/screens/Notifications.cpp | 24 +++++++++++++++--------- src/displayapp/screens/Notifications.h | 5 ++++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 8fe08a826d..3a39dacffe 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -17,6 +17,7 @@ Notifications::Notifications(DisplayApp* app, : Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, + motorController {motorController}, systemTask {systemTask}, mode {mode} { notificationManager.ClearNewNotificationFlag(); @@ -29,7 +30,8 @@ Notifications::Notifications(DisplayApp* app, notification.category, notificationManager.NbNotifications(), mode, - alertNotificationService); + alertNotificationService, + motorController); validDisplay = true; } else { currentItem = std::make_unique("Notification", @@ -38,7 +40,8 @@ Notifications::Notifications(DisplayApp* app, notification.category, notificationManager.NbNotifications(), Modes::Preview, - alertNotificationService); + alertNotificationService, + motorController); } if (mode == Modes::Preview) { @@ -66,7 +69,7 @@ Notifications::Notifications(DisplayApp* app, Notifications::~Notifications() { lv_task_del(taskRefresh); // make sure we stop any vibrations before exiting - Controllers::MotorController::StopRinging(); + motorController.StopRinging(); systemTask.PushMessage(System::Messages::EnableSleeping); lv_obj_clean(lv_scr_act()); } @@ -87,7 +90,7 @@ void Notifications::Refresh() { void Notifications::OnPreviewInteraction() { systemTask.PushMessage(System::Messages::EnableSleeping); - Controllers::MotorController::StopRinging(); + motorController.StopRinging(); if (timeoutLine != nullptr) { lv_obj_del(timeoutLine); timeoutLine = nullptr; @@ -125,7 +128,8 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { previousNotification.category, notificationManager.NbNotifications(), mode, - alertNotificationService); + alertNotificationService, + motorController); } return true; case Pinetime::Applications::TouchEvents::SwipeUp: { @@ -150,7 +154,8 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { nextNotification.category, notificationManager.NbNotifications(), mode, - alertNotificationService); + alertNotificationService, + motorController); } return true; default: @@ -171,8 +176,9 @@ Notifications::NotificationItem::NotificationItem(const char* title, Controllers::NotificationManager::Categories category, uint8_t notifNb, Modes mode, - Pinetime::Controllers::AlertNotificationService& alertNotificationService) - : mode {mode}, alertNotificationService {alertNotificationService} { + Pinetime::Controllers::AlertNotificationService& alertNotificationService, + Pinetime::Controllers::MotorController& motorController) + : mode {mode}, alertNotificationService {alertNotificationService}, motorController {motorController} { lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL); lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222)); @@ -269,7 +275,7 @@ void Notifications::NotificationItem::OnCallButtonEvent(lv_obj_t* obj, lv_event_ return; } - Controllers::MotorController::StopRinging(); + motorController.StopRinging(); if (obj == bt_accept) { alertNotificationService.AcceptIncomingCall(); diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index 2f444c7ce9..f49d3b3ac1 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -39,7 +39,8 @@ namespace Pinetime { Controllers::NotificationManager::Categories, uint8_t notifNb, Modes mode, - Pinetime::Controllers::AlertNotificationService& alertNotificationService); + Pinetime::Controllers::AlertNotificationService& alertNotificationService, + Pinetime::Controllers::MotorController& motorController); ~NotificationItem(); bool IsRunning() const { return running; @@ -56,6 +57,7 @@ namespace Pinetime { lv_obj_t* label_reject; Modes mode; Pinetime::Controllers::AlertNotificationService& alertNotificationService; + Pinetime::Controllers::MotorController& motorController; bool running = true; }; @@ -66,6 +68,7 @@ namespace Pinetime { }; Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::AlertNotificationService& alertNotificationService; + Pinetime::Controllers::MotorController& motorController; System::SystemTask& systemTask; Modes mode = Modes::Normal; std::unique_ptr currentItem; From a2a70f8eda56b4cf859f456b2f842e4833cd3dbf Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 29 Jan 2022 23:45:22 +0100 Subject: [PATCH 33/78] MotorController: no need to make this function a class function The `StopRinging()` function was used just in `Notifications.h` screen. That screen already has access to a `motorController` object. --- src/components/motor/MotorController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index c9326d57eb..b5a592b1d4 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -12,7 +12,7 @@ namespace Pinetime { void Init(); void RunForDuration(uint8_t motorDuration); void StartRinging(); - static void StopRinging(); + void StopRinging(); private: static void Ring(void* p_context); From 4aaa3a3b49b3b70509345f83ebe1c4f4bacd524d Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Tue, 15 Feb 2022 23:56:42 +0100 Subject: [PATCH 34/78] SettingShakeThreshold: add missing SystemTask.h, relative include SettingShakeThreshold.h uses SystemTask, but doesn't include the header. Fixing that for the simulator. For consistency make the header include a relative to src include. --- src/displayapp/screens/settings/SettingShakeThreshold.cpp | 2 +- src/displayapp/screens/settings/SettingShakeThreshold.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.cpp b/src/displayapp/screens/settings/SettingShakeThreshold.cpp index 1791b550e7..9d40fcf9ad 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.cpp +++ b/src/displayapp/screens/settings/SettingShakeThreshold.cpp @@ -1,4 +1,4 @@ -#include "SettingShakeThreshold.h" +#include "displayapp/screens/settings/SettingShakeThreshold.h" #include #include "displayapp/DisplayApp.h" #include "displayapp/screens/Screen.h" diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.h b/src/displayapp/screens/settings/SettingShakeThreshold.h index b9ddd8b428..37f4a65e47 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.h +++ b/src/displayapp/screens/settings/SettingShakeThreshold.h @@ -5,6 +5,7 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" #include +#include "systemtask/SystemTask.h" namespace Pinetime { namespace Applications { From b857fdb9f438cd9a3440c82face944323301cfad Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Tue, 15 Feb 2022 23:59:38 +0100 Subject: [PATCH 35/78] SystemTask: forward declare BatteryController to fix of cyclic dependency SystemTask.h included BatteryController.h, and BatteryController.h included SystemTask.h. If unlucky the class SystemTask isn't created yet when BatteryController wants to use it. Fix that cyclic dependency by forward declaring the BatteryController class and including it in the SystemTask.cpp file, where it is needed. --- src/systemtask/SystemTask.cpp | 1 + src/systemtask/SystemTask.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 6460cd4b5b..8d9cb1d101 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -4,6 +4,7 @@ #include #include "BootloaderVersion.h" +#include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "drivers/Cst816s.h" #include "drivers/St7789.h" diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index abeffd2f9e..517ed1ae90 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -13,7 +13,6 @@ #include #include "systemtask/SystemMonitor.h" -#include "components/battery/BatteryController.h" #include "components/ble/NimbleController.h" #include "components/ble/NotificationManager.h" #include "components/motor/MotorController.h" @@ -47,6 +46,7 @@ namespace Pinetime { class Hrs3300; } namespace Controllers { + class Battery; class TouchHandler; class ButtonHandler; } From f829427c4186ec003d51c689c6831d076f3b0b69 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Wed, 16 Feb 2022 22:33:59 +0100 Subject: [PATCH 36/78] Remove unused and not compiling DropDownDemo For ease of use the simulator uses a globbing expression to get all screens source files. This one was picked up as well and lead to a compilation error. --- src/CMakeLists.txt | 1 - src/displayapp/screens/DropDownDemo.cpp | 57 ------------------------- src/displayapp/screens/DropDownDemo.h | 27 ------------ 3 files changed, 85 deletions(-) delete mode 100644 src/displayapp/screens/DropDownDemo.cpp delete mode 100644 src/displayapp/screens/DropDownDemo.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aec6ce047f..39d80b050d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -626,7 +626,6 @@ set(INCLUDE_FILES displayapp/screens/InfiniPaint.h displayapp/screens/StopWatch.h displayapp/screens/Paddle.h - displayapp/screens/DropDownDemo.h displayapp/screens/BatteryIcon.h displayapp/screens/BleIcon.h displayapp/screens/NotificationIcon.h diff --git a/src/displayapp/screens/DropDownDemo.cpp b/src/displayapp/screens/DropDownDemo.cpp deleted file mode 100644 index cf239a2f4a..0000000000 --- a/src/displayapp/screens/DropDownDemo.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "displayapp/screens/DropDownDemo.h" -#include -#include -#include "displayapp/DisplayApp.h" - -using namespace Pinetime::Applications::Screens; - -DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp* app) : Screen(app) { - // Create the dropdown object, with many item, and fix its height - ddlist = lv_ddlist_create(lv_scr_act(), nullptr); - lv_ddlist_set_options(ddlist, - "Apple\n" - "Banana\n" - "Orange\n" - "Melon\n" - "Grape\n" - "Raspberry\n" - "A\n" - "B\n" - "C\n" - "D\n" - "E"); - lv_ddlist_set_fix_width(ddlist, 150); - lv_ddlist_set_draw_arrow(ddlist, true); - lv_ddlist_set_fix_height(ddlist, 150); - lv_obj_align(ddlist, nullptr, LV_ALIGN_IN_TOP_MID, 0, 20); -} - -DropDownDemo::~DropDownDemo() { - // Reset the touchmode - app->SetTouchMode(DisplayApp::TouchModes::Gestures); - lv_obj_clean(lv_scr_act()); -} - -bool DropDownDemo::Refresh() { - auto* list = static_cast(ddlist->ext_attr); - - // Switch touchmode to Polling if the dropdown is opened. This will allow to scroll inside the - // dropdown while it is opened. - // Disable the polling mode when the dropdown is closed to be able to handle the gestures. - if (list->opened) - app->SetTouchMode(DisplayApp::TouchModes::Polling); - else - app->SetTouchMode(DisplayApp::TouchModes::Gestures); - return running; -} - -bool DropDownDemo::OnTouchEvent(Pinetime::Applications::TouchEvents event) { - // If the dropdown is opened, notify Display app that it doesn't need to handle the event - // (this will prevent displayApp from going back to the menu or clock scree). - auto* list = static_cast(ddlist->ext_attr); - if (list->opened) { - return true; - } else { - return false; - } -} diff --git a/src/displayapp/screens/DropDownDemo.h b/src/displayapp/screens/DropDownDemo.h deleted file mode 100644 index bcf0f45c92..0000000000 --- a/src/displayapp/screens/DropDownDemo.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include "displayapp/screens/Screen.h" -#include - -namespace Pinetime { - namespace Applications { - namespace Screens { - - class DropDownDemo : public Screen { - public: - DropDownDemo(DisplayApp* app); - ~DropDownDemo() override; - - bool Refresh() override; - - bool OnTouchEvent(TouchEvents event) override; - - private: - lv_obj_t* ddlist; - - bool isDropDownOpened = false; - }; - } - } -} From 407908686ac252615f35e5175fcb0c2fd19cce69 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 30 Jan 2022 14:31:13 +0100 Subject: [PATCH 37/78] Provide reference to BrightnessController in DisplayApp For the simulator I need a way to get to the brightnessController object and handle the set brightness-levels accoringly. This is done by the constructor expecting a brightnessController object instead of initializing one itself --- src/displayapp/DisplayApp.cpp | 2 ++ src/displayapp/DisplayApp.h | 3 ++- src/displayapp/DisplayAppRecovery.cpp | 1 + src/displayapp/DisplayAppRecovery.h | 2 ++ src/main.cpp | 3 +++ 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 495969b3eb..fdd1682bcd 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -97,6 +97,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, lvgl {lvgl}, @@ -112,6 +113,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, motionController {motionController}, timerController {timerController}, alarmController {alarmController}, + brightnessController {brightnessController}, touchHandler {touchHandler} { } diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 39fe631455..1eaefaa106 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -61,6 +61,7 @@ namespace Pinetime { Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(System::BootErrors error); void PushMessage(Display::Messages msg); @@ -87,10 +88,10 @@ namespace Pinetime { Pinetime::Controllers::MotionController& motionController; Pinetime::Controllers::TimerController& timerController; Pinetime::Controllers::AlarmController& alarmController; + Pinetime::Controllers::BrightnessController &brightnessController; Pinetime::Controllers::TouchHandler& touchHandler; Pinetime::Controllers::FirmwareValidator validator; - Controllers::BrightnessController brightnessController; TaskHandle_t taskHandle; diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index fd7017a451..9d6eb22f68 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -23,6 +23,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, bleController {bleController} { diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 86e956d133..61f1c9bf5c 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -34,6 +34,7 @@ namespace Pinetime { class MotorController; class TimerController; class AlarmController; + class BrightnessController; } namespace System { @@ -57,6 +58,7 @@ namespace Pinetime { Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(); void Start(Pinetime::System::BootErrors){ Start(); }; diff --git a/src/main.cpp b/src/main.cpp index 81d297f5ad..fa492d08e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,6 +33,7 @@ #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/ble/NotificationManager.h" +#include "components/brightness/BrightnessController.h" #include "components/motor/MotorController.h" #include "components/datetime/DateTimeController.h" #include "components/heartrate/HeartRateController.h" @@ -114,6 +115,7 @@ Pinetime::Controllers::TimerController timerController; Pinetime::Controllers::AlarmController alarmController {dateTimeController}; Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl); Pinetime::Controllers::ButtonHandler buttonHandler; +Pinetime::Controllers::BrightnessController brightnessController {}; Pinetime::Applications::DisplayApp displayApp(lcd, lvgl, @@ -129,6 +131,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd, motionController, timerController, alarmController, + brightnessController, touchHandler); Pinetime::System::SystemTask systemTask(spi, From 69e4ab6be101e7993035b56db75f5c32eda713ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sun, 20 Feb 2022 13:20:43 +0100 Subject: [PATCH 38/78] Manual squash merge of PR #932 (https://github.com/InfiniTimeOrg/InfiniTime/pull/932) from 13werwolf13 (https://github.com/13werwolf13). This PR adds a new Terminal watchface to InfiniTime! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commit of the following: commit 23ea840b059c69667c8711265cecaf992791acb6 Author: Jean-François Milants Date: Sun Feb 20 13:14:27 2022 +0100 Terminal watch face : fix includes and a few code cleaning. commit 3c244def25e3ad8e1f56d708fb0864c122059948 Merge: 40790868 138a6552 Author: Jean-François Milants Date: Sun Feb 20 12:45:54 2022 +0100 Merge branch 'develop' of https://github.com/13werwolf13/InfiniTime into 13werwolf13-develop commit 138a65528a86799fd5c37f065023a92f222fe044 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:13:00 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.h Co-authored-by: NeroBurner commit 35156166b2f7589bf005ec7c7192a4226578f6d9 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:12:43 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 757ca2dd438f1f314267a8b81a6034c576f1d6be Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:12:30 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 60b6b4e5824d04faa3efa45173358d04fa68a368 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:12:20 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 6959d8c043013550a7a3e4e6588b234d3bb942b5 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:11:46 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 4d850281bedf342d0856da5eafc22e46d0767c56 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:11:17 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit af483bee33c225fcb03432db1eb14c0453df0ae7 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:10:57 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 6bc6c1a637be4e514ecd0097d1dc9e4aacdba1db Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:10:40 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.h Co-authored-by: NeroBurner commit 25fdafc6aba0d9e0173103501de3802af261e2ae Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:06:10 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 12e1b0f8c0202a7f62e3e1c297af850ce3526d13 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:05:44 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit e6c0f32056e9fea878d270d761607ac5ddc263b0 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:05:22 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.h Co-authored-by: NeroBurner commit 342ce8cd114f4af265078bc0cfa6b2d8831706d7 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:05:06 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 265fec5eeca27fcc1152a18e4af0273bcf119c46 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:04:06 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit b4669be38be0df2b6a3505d5f7a770c71636be60 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:03:29 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 471a84390957ded2ac23ebfe1cb99408e3783b0f Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:03:10 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit 6853166cf546a4ce561195eba01f1b1fd6d56420 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Wed Feb 2 09:02:51 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit bba34f69bfdd6b44f142c93644f71c9eda007290 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Sat Jan 22 12:32:41 2022 +0500 some fixes commit 74eea9f5800f273249846e6e1c887d15ba6eb10b Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Sat Jan 22 12:32:17 2022 +0500 some fixes commit 1e4a6763d73c3ba39c680ad25f90813e6a6a36d1 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Fri Jan 21 08:59:44 2022 +0500 no errors, no warnings, no work.. commit eb8bd4dc4ecbbf61f1e0f725fd2116ee25319fd6 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 20 23:50:04 2022 +0500 add ble state text output commit fda1c088becb4a7f9ced451a0291694abe2249dc Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 20 22:25:35 2022 +0500 add ble state text output commit 68d3d9b343c0f37830bb640fab10b186faf73067 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 20 22:22:20 2022 +0500 add ble state text output commit 0ed45a9916787f68c0aa6bab9c97b090f2eebdd5 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Tue Jan 18 15:48:15 2022 +0500 typo fix commit 477a3a7f27c7486be2c8f985afab1f1739608fed Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Tue Jan 18 10:36:19 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit d6849888ea5cc152f04c5bf6fe2631e66296c357 Author: Марков Дмитрий <13werwolf13@mail.ru> Date: Tue Jan 18 10:36:09 2022 +0500 Update src/displayapp/screens/WatchFaceTerminal.cpp Co-authored-by: NeroBurner commit e2f7e318298b8a6f4d436cbbb1b92a738dacab7f Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Mon Jan 17 13:34:05 2022 +0500 typo fix commit fc246beb01d3feac4fd0b2fc9c45b38847e1d950 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Sat Jan 15 15:26:25 2022 +0500 typo fix commit ebbb31abf10ad9f61a8a7ecfdf29c2aaeaf33c19 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Fri Jan 14 10:08:29 2022 +0500 typo fix commit 3afedcaa28009f59e6960730e9349097ef455ea8 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 13 12:34:39 2022 +0500 time format commit 471a4c942f7e3cfd5c52bd61152ede770da5e026 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 13 12:27:10 2022 +0500 time format commit d3fd348de4b4a89c216a717de84fcc923cc099fe Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 13 12:26:49 2022 +0500 time format commit e540d103e3204649ff585742f8834d16136372d5 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Thu Jan 13 11:28:31 2022 +0500 add patch commit 728830178f31f71785c49cdc6b83daea4e0a7df6 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Wed Jan 12 22:08:07 2022 +0500 add menue item commit 4c5847669fa083f15ee3fdb404dadfdaef0f82aa Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Wed Jan 12 21:42:22 2022 +0500 typo fix commit 79273fe24f9162aca5508f07b17896149ad19839 Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Wed Jan 12 20:48:06 2022 +0500 typo fix commit 1808a78ad94d0dfe97b6410a93ba30560de22f4b Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Wed Jan 12 20:17:15 2022 +0500 typo fix commit 6dfa141dca176789da4e978f008eb842d9ec515a Author: Дмитрий Марков Date: Wed Jan 12 20:12:09 2022 +0500 typo fix commit 88f01902325505a9206ced4504aae0762042535d Author: Дмитрий Марков <13werwolf13@mail.ru> Date: Wed Jan 12 14:50:54 2022 +0500 add terminal watchface --- src/CMakeLists.txt | 1 + src/components/heartrate/Ppg.h | 2 + src/displayapp/screens/Clock.cpp | 24 ++- src/displayapp/screens/Clock.h | 1 + src/displayapp/screens/WatchFaceTerminal.cpp | 198 ++++++++++++++++++ src/displayapp/screens/WatchFaceTerminal.h | 82 ++++++++ .../screens/settings/SettingWatchFace.cpp | 2 +- .../screens/settings/SettingWatchFace.h | 2 +- 8 files changed, 303 insertions(+), 9 deletions(-) create mode 100644 src/displayapp/screens/WatchFaceTerminal.cpp create mode 100644 src/displayapp/screens/WatchFaceTerminal.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39d80b050d..5986d95f92 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -454,6 +454,7 @@ list(APPEND SOURCE_FILES displayapp/icons/bg_clock.c displayapp/screens/WatchFaceAnalog.cpp displayapp/screens/WatchFaceDigital.cpp + displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/PineTimeStyle.cpp ## diff --git a/src/components/heartrate/Ppg.h b/src/components/heartrate/Ppg.h index ed79b08220..7000c8710b 100644 --- a/src/components/heartrate/Ppg.h +++ b/src/components/heartrate/Ppg.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include "components/heartrate/Biquad.h" #include "components/heartrate/Ptagc.h" diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index 1415e8ec0c..fd74683a79 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -9,6 +9,7 @@ #include "components/settings/Settings.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/WatchFaceDigital.h" +#include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceAnalog.h" #include "displayapp/screens/PineTimeStyle.h" @@ -41,6 +42,9 @@ Clock::Clock(DisplayApp* app, case 2: return PineTimeStyleScreen(); break; + case 3: + return WatchFaceTerminalScreen(); + break; } return WatchFaceDigitalScreen(); }()} { @@ -76,11 +80,17 @@ std::unique_ptr Clock::WatchFaceAnalogScreen() { } std::unique_ptr Clock::PineTimeStyleScreen() { - return std::make_unique(app, - dateTimeController, - batteryController, - bleController, - notificatioManager, - settingsController, - motionController); + return std::make_unique( + app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, motionController); +} + +std::unique_ptr Clock::WatchFaceTerminalScreen() { + return std::make_unique(app, + dateTimeController, + batteryController, + bleController, + notificatioManager, + settingsController, + heartRateController, + motionController); } diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h index fcecc6b3d9..50996a7391 100644 --- a/src/displayapp/screens/Clock.h +++ b/src/displayapp/screens/Clock.h @@ -47,6 +47,7 @@ namespace Pinetime { std::unique_ptr WatchFaceDigitalScreen(); std::unique_ptr WatchFaceAnalogScreen(); std::unique_ptr PineTimeStyleScreen(); + std::unique_ptr WatchFaceTerminalScreen(); }; } } diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp new file mode 100644 index 0000000000..033aad88ad --- /dev/null +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -0,0 +1,198 @@ +#include +#include +#include "displayapp/screens/WatchFaceTerminal.h" +#include "displayapp/screens/BatteryIcon.h" +#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" + +using namespace Pinetime::Applications::Screens; + +WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, + Controllers::DateTime& dateTimeController, + Controllers::Battery& batteryController, + Controllers::Ble& bleController, + Controllers::NotificationManager& notificatioManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController) + : Screen(app), + currentDateTime {{}}, + dateTimeController {dateTimeController}, + batteryController {batteryController}, + bleController {bleController}, + notificatioManager {notificatioManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController} { + settingsController.SetClockFace(3); + + batteryIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text(batteryIcon, Symbols::batteryFull); + lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, 2); + + batteryPlug = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text(batteryPlug, Symbols::plug); + lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); + + 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); + + connectState = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_recolor(connectState, true); + lv_label_set_text(connectState, "[STAT]#387b54 Disconnected#"); + lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); + + notificationIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0); + + label_date = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_recolor(label_date, true); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -40); + + label_prompt_1 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_prompt_1, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -80); + lv_label_set_text(label_prompt_1, "user@watch:~ $ now"); + + label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); + lv_label_set_text(label_prompt_2, "user@watch:~ $"); + + label_time = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_recolor(label_time, true); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -60); + + backgroundLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_click(backgroundLabel, true); + lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); + lv_obj_set_size(backgroundLabel, 240, 240); + lv_obj_set_pos(backgroundLabel, 0, 0); + lv_label_set_text(backgroundLabel, ""); + + heartbeatValue = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_recolor(heartbeatValue, true); + lv_label_set_text(heartbeatValue, "[L_HR]#ee3311 0 bpm#"); + lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20); + + stepValue = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_recolor(stepValue, true); + lv_label_set_text(stepValue, "[STEP]#ee3377 0 steps#"); + lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceTerminal::~WatchFaceTerminal() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceTerminal::Refresh() { + powerPresent = batteryController.IsPowerPresent(); + if (powerPresent.IsUpdated()) { + lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get())); + } + + batteryPercentRemaining = batteryController.PercentRemaining(); + if (batteryPercentRemaining.IsUpdated()) { + auto batteryPercent = batteryPercentRemaining.Get(); + if (batteryPercent == 100) { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + } else { + lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + } + lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); + lv_label_set_text_fmt(batteryValue, "[BATT]#387b54 %d%\%#", batteryPercent); + } + + bleState = bleController.IsConnected(); + if (bleState.IsUpdated()) { + if (bleState.Get()) { + lv_label_set_text_static(connectState, "[STAT]#387b54 Connected#"); + } else { + lv_label_set_text_static(connectState, "[STAT]#387b54 Disconnected#"); + } + } + + notificationState = notificatioManager.AreNewNotificationsAvailable(); + if (notificationState.IsUpdated()) { + if (notificationState.Get()) { + lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true)); + } else { + lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + } + } + + currentDateTime = dateTimeController.CurrentDateTime(); + + if (currentDateTime.IsUpdated()) { + auto newDateTime = currentDateTime.Get(); + + auto dp = date::floor(newDateTime); + auto time = date::make_time(newDateTime - dp); + auto yearMonthDay = date::year_month_day(dp); + + auto year = static_cast(yearMonthDay.year()); + auto month = static_cast(static_cast(yearMonthDay.month())); + auto day = static_cast(yearMonthDay.day()); + auto dayOfWeek = static_cast(date::weekday(yearMonthDay).iso_encoding()); + + uint8_t hour = time.hours().count(); + uint8_t minute = time.minutes().count(); + uint8_t second = time.seconds().count(); + + if (displayedHour != hour || displayedMinute != minute || displayedSecond != second) { + displayedHour = hour; + displayedMinute = minute; + displayedSecond = second; + + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + char ampmChar[3] = "AM"; + if (hour == 0) { + hour = 12; + } else if (hour == 12) { + ampmChar[0] = 'P'; + } else if (hour > 12) { + hour = hour - 12; + ampmChar[0] = 'P'; + } + lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); + } else { + lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d", hour, minute, second); + } + } + + if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { + lv_label_set_text_fmt(label_date, "[DATE]#007fff %04d.%02d.%02d#", short(year), char(month), char(day)); + + currentYear = year; + currentMonth = month; + currentDayOfWeek = dayOfWeek; + currentDay = day; + } + } + + heartbeat = heartRateController.HeartRate(); + heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; + if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { + if (heartbeatRunning.Get()) { + lv_label_set_text_fmt(heartbeatValue, "[L_HR]#ee3311 %d bpm#", heartbeat.Get()); + } else { + lv_label_set_text_static(heartbeatValue, "[L_HR]#ee3311 ---#"); + } + } + + stepCount = motionController.NbSteps(); + motionSensorOk = motionController.IsSensorOk(); + if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) { + lv_label_set_text_fmt(stepValue, "[STEP]#ee3377 %lu steps#", stepCount.Get()); + } +} diff --git a/src/displayapp/screens/WatchFaceTerminal.h b/src/displayapp/screens/WatchFaceTerminal.h new file mode 100644 index 0000000000..c3df82b42a --- /dev/null +++ b/src/displayapp/screens/WatchFaceTerminal.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + + namespace Applications { + namespace Screens { + + class WatchFaceTerminal : public Screen { + public: + WatchFaceTerminal(DisplayApp* app, + Controllers::DateTime& dateTimeController, + Controllers::Battery& batteryController, + Controllers::Ble& bleController, + Controllers::NotificationManager& notificatioManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController); + ~WatchFaceTerminal() override; + + void Refresh() override; + + private: + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; + uint8_t displayedSecond = -1; + + uint16_t currentYear = 1970; + Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; + Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; + uint8_t currentDay = 0; + + DirtyValue batteryPercentRemaining {}; + DirtyValue powerPresent {}; + DirtyValue bleState {}; + DirtyValue> currentDateTime {}; + DirtyValue motionSensorOk {}; + DirtyValue stepCount {}; + DirtyValue heartbeat {}; + DirtyValue heartbeatRunning {}; + DirtyValue notificationState {}; + + lv_obj_t* label_time; + lv_obj_t* label_date; + lv_obj_t* label_prompt_1; + lv_obj_t* label_prompt_2; + lv_obj_t* backgroundLabel; + lv_obj_t* batteryIcon; + lv_obj_t* batteryPlug; + lv_obj_t* batteryValue; + lv_obj_t* heartbeatValue; + lv_obj_t* stepValue; + lv_obj_t* notificationIcon; + lv_obj_t* connectState; + + Controllers::DateTime& dateTimeController; + Controllers::Battery& batteryController; + Controllers::Ble& bleController; + Controllers::NotificationManager& notificatioManager; + Controllers::Settings& settingsController; + Controllers::HeartRateController& heartRateController; + Controllers::MotionController& motionController; + + lv_task_t* taskRefresh; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index a24eaa1539..5008592522 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -14,7 +14,7 @@ namespace { } } -constexpr std::array SettingWatchFace::options; +constexpr std::array SettingWatchFace::options; SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) : Screen(app), settingsController {settingsController} { diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index ccba7d13d3..62427b4f20 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -20,7 +20,7 @@ namespace Pinetime { void UpdateSelected(lv_obj_t* object, lv_event_t event); private: - static constexpr std::array options = {" Digital face", " Analog face", " PineTimeStyle"}; + static constexpr std::array options = {" Digital face", " Analog face", " PineTimeStyle", " Terminal"}; Controllers::Settings& settingsController; lv_obj_t* cbOption[options.size()]; From ef44b763d94cc6ff1be6f75ff3e638d7d356e99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sun, 20 Feb 2022 15:40:49 +0100 Subject: [PATCH 39/78] Merge branch 'airplane-mode' of https://github.com/evergreen22/InfiniTime into evergreen22-airplane-mode Apply a few changes that were requested in the PR during the review. # Conflicts: # src/CMakeLists.txt # src/displayapp/Apps.h # src/displayapp/DisplayApp.cpp # src/displayapp/Messages.h # src/displayapp/screens/settings/Settings.cpp --- src/components/ble/BleController.cpp | 24 +++++- src/components/ble/BleController.h | 16 ++-- src/components/ble/NimbleController.cpp | 35 ++++----- src/components/ble/NimbleController.h | 15 +--- src/components/settings/Settings.h | 10 +-- src/displayapp/DisplayApp.cpp | 4 +- src/displayapp/Messages.h | 2 +- src/displayapp/screens/BleIcon.cpp | 15 ++-- src/displayapp/screens/BleIcon.h | 2 +- src/displayapp/screens/PineTimeStyle.cpp | 20 +++-- src/displayapp/screens/PineTimeStyle.h | 3 +- src/displayapp/screens/WatchFaceDigital.cpp | 7 +- src/displayapp/screens/WatchFaceDigital.h | 3 +- src/displayapp/screens/WatchFaceTerminal.cpp | 13 +++- src/displayapp/screens/WatchFaceTerminal.h | 1 + .../screens/settings/SettingAirplaneMode.cpp | 74 ++++++++++--------- .../screens/settings/SettingAirplaneMode.h | 7 +- src/displayapp/screens/settings/Settings.cpp | 37 +++++++--- src/displayapp/screens/settings/Settings.h | 3 +- src/systemtask/Messages.h | 2 +- src/systemtask/SystemTask.cpp | 10 ++- 21 files changed, 179 insertions(+), 124 deletions(-) diff --git a/src/components/ble/BleController.cpp b/src/components/ble/BleController.cpp index 0e1c5d7e5e..b6b7383a3c 100644 --- a/src/components/ble/BleController.cpp +++ b/src/components/ble/BleController.cpp @@ -2,12 +2,28 @@ using namespace Pinetime::Controllers; -void Ble::SetConnectState(Ble::ConnectStates newState) { - connectionState = newState; +bool Ble::IsConnected() const { + return isConnected; } -Ble::ConnectStates Ble::GetConnectState() const { - return connectionState; +void Ble::Connect() { + isConnected = true; +} + +void Ble::Disconnect() { + isConnected = false; +} + +bool Ble::IsRadioEnabled() const { + return isRadioEnabled; +} + +void Ble::EnableRadio() { + isRadioEnabled = true; +} + +void Ble::DisableRadio() { + isRadioEnabled = false; } void Ble::StartFirmwareUpdate() { diff --git a/src/components/ble/BleController.h b/src/components/ble/BleController.h index 2714c0c3c7..675ede2d63 100644 --- a/src/components/ble/BleController.h +++ b/src/components/ble/BleController.h @@ -10,14 +10,15 @@ namespace Pinetime { using BleAddress = std::array; enum class FirmwareUpdateStates { Idle, Running, Validated, Error }; enum class AddressTypes { Public, Random, RPA_Public, RPA_Random }; - enum class ConnectStates { Disconnected, Connected, Airplane }; Ble() = default; - bool IsConnected() const { - return (connectionState == ConnectStates::Connected); - } - void SetConnectState(ConnectStates newState); - ConnectStates GetConnectState() const; + bool IsConnected() const; + void Connect(); + void Disconnect(); + + bool IsRadioEnabled() const; + void EnableRadio(); + void DisableRadio(); void StartFirmwareUpdate(); void StopFirmwareUpdate(); @@ -57,7 +58,8 @@ namespace Pinetime { } private: - ConnectStates connectionState = ConnectStates::Disconnected; + bool isConnected = false; + bool isRadioEnabled = true; bool isFirmwareUpdating = false; uint32_t firmwareUpdateTotalBytes = 0; uint32_t firmwareUpdateCurrentBytes = 0; diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 94d2d15579..f6ab626928 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -184,7 +184,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { case BLE_GAP_EVENT_ADV_COMPLETE: NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE"); NRF_LOG_INFO("reason=%d; status=%0X", event->adv_complete.reason, event->connect.status); - if (bleController.GetConnectState() == Ble::ConnectStates::Disconnected) { + if (bleController.IsRadioEnabled() && !bleController.IsConnected()) { StartAdvertising(); } break; @@ -199,12 +199,12 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { currentTimeClient.Reset(); alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; - bleController.SetConnectState(Ble::ConnectStates::Disconnected); + bleController.Disconnect(); fastAdvCount = 0; StartAdvertising(); } else { connectionHandle = event->connect.conn_handle; - bleController.SetConnectState(Ble::ConnectStates::Connected); + bleController.Connect(); systemTask.PushMessage(Pinetime::System::Messages::BleConnected); // Service discovery is deferred via systemtask } @@ -222,8 +222,8 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { currentTimeClient.Reset(); alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; - if (bleController.GetConnectState() == Ble::ConnectStates::Connected) { - bleController.SetConnectState(Ble::ConnectStates::Disconnected); + if(bleController.IsConnected()) { + bleController.Disconnect(); fastAdvCount = 0; StartAdvertising(); } @@ -401,19 +401,20 @@ void NimbleController::NotifyBatteryLevel(uint8_t level) { } } -void NimbleController::SwitchAirplaneMode(bool enabled) { - if (enabled) { - if (bleController.IsConnected()) { - bleController.SetConnectState(Ble::ConnectStates::Airplane); - ble_gap_terminate(connectionHandle, BLE_ERR_REM_USER_CONN_TERM); - } else { - bleController.SetConnectState(Ble::ConnectStates::Airplane); - ble_gap_adv_stop(); - } +void NimbleController::EnableRadio() { + bleController.EnableRadio(); + bleController.Disconnect(); + fastAdvCount = 0; + StartAdvertising(); +} + +void NimbleController::DisableRadio() { + bleController.DisableRadio(); + if (bleController.IsConnected()) { + ble_gap_terminate(connectionHandle, BLE_ERR_REM_USER_CONN_TERM); + bleController.Disconnect(); } else { - bleController.SetConnectState(Ble::ConnectStates::Disconnected); - fastAdvCount = 0; - StartAdvertising(); + ble_gap_adv_stop(); } } diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 7219ba6b86..ad1942121a 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -53,18 +53,6 @@ namespace Pinetime { void Init(); void StartAdvertising(); int OnGAPEvent(ble_gap_event* event); - - /* these are not implemented yet - int OnDiscoveryEvent(uint16_t i, const ble_gatt_error* pError, const ble_gatt_svc* pSvc); - int OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); - int OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); - int OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute); - int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, - const ble_gatt_error* error, - uint16_t characteristicValueHandle, - const ble_gatt_dsc* descriptor); - */ - void StartDiscovery(); Pinetime::Controllers::MusicService& music() { @@ -87,7 +75,8 @@ namespace Pinetime { fastAdvCount = 0; }; - void SwitchAirplaneMode(bool enabled); + void EnableRadio(); + void DisableRadio(); private: void PersistBond(struct ble_gap_conn_desc& desc); diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 9878aac5cd..24a826072f 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -202,12 +202,12 @@ namespace Pinetime { return settings.stepsGoal; }; - void SetAirplaneMode(bool mode) { - airplaneMode = mode; + void SetBleRadioEnabled(bool enabled) { + bleRadioEnabled = enabled; }; - bool GetAirplaneMode() const { - return airplaneMode; + bool GetBleRadioEnabled() const { + return bleRadioEnabled; }; private: @@ -240,7 +240,7 @@ namespace Pinetime { /* airplaneMode is intentionally not saved with the other watch settings and initialized * to off (false) on every boot because we always want ble to be enabled on startup */ - bool airplaneMode = false; + bool bleRadioEnabled = true; void LoadSettingsFromFile(); void SaveSettingsToFile(); diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 25ae9ad65d..fdc6376c5d 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -293,8 +293,8 @@ void DisplayApp::Refresh() { case Messages::BleFirmwareUpdateStarted: LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); break; - case Messages::AirplaneModeToggle: - PushMessageToSystemTask(System::Messages::AirplaneModeToggle); + case Messages::BleRadioEnableToggle: + PushMessageToSystemTask(System::Messages::BleRadioEnableToggle); break; case Messages::UpdateDateTime: // Added to remove warning diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index 62256b9e66..58df45565e 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -22,7 +22,7 @@ namespace Pinetime { ShowPairingKey, AlarmTriggered, Clock, - AirplaneModeToggle + BleRadioEnableToggle }; } } diff --git a/src/displayapp/screens/BleIcon.cpp b/src/displayapp/screens/BleIcon.cpp index a30d23bdfe..019f80397f 100644 --- a/src/displayapp/screens/BleIcon.cpp +++ b/src/displayapp/screens/BleIcon.cpp @@ -2,11 +2,14 @@ #include "displayapp/screens/Symbols.h" using namespace Pinetime::Applications::Screens; -const char* BleIcon::GetIcon(Pinetime::Controllers::Ble::ConnectStates state) { - if (state == Pinetime::Controllers::Ble::ConnectStates::Connected) - return Symbols::bluetooth; - else if (state == Pinetime::Controllers::Ble::ConnectStates::Airplane) +const char* BleIcon::GetIcon(bool isRadioEnabled, bool isConnected) { + if(!isRadioEnabled) { return Symbols::airplane; - else - return Symbols::none; + } + + if (isConnected) { + return Symbols::bluetooth; + } + + return Symbols::none; } diff --git a/src/displayapp/screens/BleIcon.h b/src/displayapp/screens/BleIcon.h index d7410eae2f..d32dfad7ee 100644 --- a/src/displayapp/screens/BleIcon.h +++ b/src/displayapp/screens/BleIcon.h @@ -7,7 +7,7 @@ namespace Pinetime { namespace Screens { class BleIcon { public: - static const char* GetIcon(Pinetime::Controllers::Ble::ConnectStates state); + static const char* GetIcon(bool isRadioEnabled, bool isConnected); }; } } diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp index f1f7f922ab..44bf47a4f5 100644 --- a/src/displayapp/screens/PineTimeStyle.cpp +++ b/src/displayapp/screens/PineTimeStyle.cpp @@ -42,6 +42,13 @@ namespace { auto* screen = static_cast(obj->user_data); screen->UpdateSelected(obj, event); } + + bool IsBleIconVisible(bool isRadioEnabled, bool isConnected) { + if(!isRadioEnabled) { + return true; + } + return isConnected; + } } PineTimeStyle::PineTimeStyle(DisplayApp* app, @@ -336,11 +343,13 @@ void PineTimeStyle::SetBatteryIcon() { lv_label_set_text_static(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); } + void PineTimeStyle::AlignIcons() { - if (notificationState.Get() && bleState.Get() != Pinetime::Controllers::Ble::ConnectStates::Disconnected) { + bool isBleIconVisible = IsBleIconVisible(bleRadioEnabled.Get(), bleState.Get()); + if (notificationState.Get() && isBleIconVisible) { lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 8, 25); lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, -8, 25); - } else if (notificationState.Get() && bleState.Get() == Pinetime::Controllers::Ble::ConnectStates::Disconnected) { + } else if (notificationState.Get() && !isBleIconVisible) { lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); } else { lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); @@ -363,9 +372,10 @@ void PineTimeStyle::Refresh() { } } - bleState = bleController.GetConnectState(); - if (bleState.IsUpdated()) { - lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); + bleState = bleController.IsConnected(); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + lv_label_set_text(bleIcon, BleIcon::GetIcon(bleRadioEnabled.Get(), bleState.Get())); AlignIcons(); } diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h index cb8f6804fd..5de9a5fa1b 100644 --- a/src/displayapp/screens/PineTimeStyle.h +++ b/src/displayapp/screens/PineTimeStyle.h @@ -51,7 +51,8 @@ namespace Pinetime { DirtyValue batteryPercentRemaining {}; DirtyValue isCharging {}; - DirtyValue bleState {}; + DirtyValue bleState {}; + DirtyValue bleRadioEnabled {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; DirtyValue stepCount {}; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index fd36aa22f4..56155d52a3 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -119,9 +119,10 @@ void WatchFaceDigital::Refresh() { lv_label_set_text_static(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); } - bleState = bleController.GetConnectState(); - if (bleState.IsUpdated()) { - lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); + bleState = bleController.IsConnected(); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + lv_label_set_text(bleIcon, BleIcon::GetIcon(bleRadioEnabled.Get(), bleState.Get())); } lv_obj_realign(batteryIcon); lv_obj_realign(batteryPlug); diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 6cf1131027..d33434c07b 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -46,7 +46,8 @@ namespace Pinetime { DirtyValue batteryPercentRemaining {}; DirtyValue powerPresent {}; - DirtyValue bleState {}; + DirtyValue bleState {}; + DirtyValue bleRadioEnabled {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; DirtyValue stepCount {}; diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 033aad88ad..ccfbdd0baa 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -114,11 +114,16 @@ void WatchFaceTerminal::Refresh() { } bleState = bleController.IsConnected(); - if (bleState.IsUpdated()) { - if (bleState.Get()) { - lv_label_set_text_static(connectState, "[STAT]#387b54 Connected#"); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + if(!bleRadioEnabled.Get()) { + lv_label_set_text_static(connectState, "[STAT]#387b54 Disabled#"); } else { - lv_label_set_text_static(connectState, "[STAT]#387b54 Disconnected#"); + if (bleState.Get()) { + lv_label_set_text_static(connectState, "[STAT]#387b54 Connected#"); + } else { + lv_label_set_text_static(connectState, "[STAT]#387b54 Disconnected#"); + } } } diff --git a/src/displayapp/screens/WatchFaceTerminal.h b/src/displayapp/screens/WatchFaceTerminal.h index c3df82b42a..78c7b8aa82 100644 --- a/src/displayapp/screens/WatchFaceTerminal.h +++ b/src/displayapp/screens/WatchFaceTerminal.h @@ -47,6 +47,7 @@ namespace Pinetime { DirtyValue batteryPercentRemaining {}; DirtyValue powerPresent {}; DirtyValue bleState {}; + DirtyValue bleRadioEnabled {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; DirtyValue stepCount {}; diff --git a/src/displayapp/screens/settings/SettingAirplaneMode.cpp b/src/displayapp/screens/settings/SettingAirplaneMode.cpp index 0a364ded59..85172787b4 100644 --- a/src/displayapp/screens/settings/SettingAirplaneMode.cpp +++ b/src/displayapp/screens/settings/SettingAirplaneMode.cpp @@ -9,13 +9,16 @@ using namespace Pinetime::Applications::Screens; namespace { - static void event_handler(lv_obj_t* obj, lv_event_t event) { - SettingAirplaneMode* screen = static_cast(obj->user_data); - screen->UpdateSelected(obj, event); + static void OnAirplaneModeEnabledEvent(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnAirplaneModeEnabled(obj, event); } -} -constexpr std::array SettingAirplaneMode::options; + static void OnAirplaneModeDisabledEvent(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnAirplaneModeDisabled(obj, event); + } +} SettingAirplaneMode::SettingAirplaneMode(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) : Screen(app), settingsController {settingsController} { @@ -43,47 +46,48 @@ SettingAirplaneMode::SettingAirplaneMode(Pinetime::Applications::DisplayApp* app 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]); - } + cbEnabled = lv_checkbox_create(container1, nullptr); + lv_checkbox_set_text(cbEnabled, " Enable"); + cbEnabled->user_data = this; + lv_obj_set_event_cb(cbEnabled, OnAirplaneModeEnabledEvent); + SetRadioButtonStyle(cbEnabled); - if (settingsController.GetAirplaneMode() == false) { - lv_checkbox_set_checked(cbOption[0], true); - priorMode = false; - } else { - lv_checkbox_set_checked(cbOption[1], true); + cbDisabled = lv_checkbox_create(container1, nullptr); + lv_checkbox_set_text(cbDisabled, " Disable"); + cbDisabled->user_data = this; + lv_obj_set_event_cb(cbDisabled, OnAirplaneModeDisabledEvent); + SetRadioButtonStyle(cbDisabled); + + if (settingsController.GetBleRadioEnabled()) { + lv_checkbox_set_checked(cbDisabled, true); priorMode = true; + } else { + lv_checkbox_set_checked(cbEnabled, true); + priorMode = false; } } SettingAirplaneMode::~SettingAirplaneMode() { lv_obj_clean(lv_scr_act()); // Do not call SaveSettings - see src/components/settings/Settings.h - if (priorMode != settingsController.GetAirplaneMode()) { - app->PushMessage(Pinetime::Applications::Display::Messages::AirplaneModeToggle); + if (priorMode != settingsController.GetBleRadioEnabled()) { + app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle); } } -void SettingAirplaneMode::UpdateSelected(lv_obj_t* object, lv_event_t event) { +void SettingAirplaneMode::OnAirplaneModeEnabled(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.SetAirplaneMode(false); - }; - if (i == 1) { - settingsController.SetAirplaneMode(true); - }; - - } else { - lv_checkbox_set_checked(cbOption[i], false); - } - } + lv_checkbox_set_checked(cbEnabled, true); + lv_checkbox_set_checked(cbDisabled, false); + settingsController.SetBleRadioEnabled(false); } } + +void SettingAirplaneMode::OnAirplaneModeDisabled(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(true); + } +} + diff --git a/src/displayapp/screens/settings/SettingAirplaneMode.h b/src/displayapp/screens/settings/SettingAirplaneMode.h index fcc0222865..b3478c64fd 100644 --- a/src/displayapp/screens/settings/SettingAirplaneMode.h +++ b/src/displayapp/screens/settings/SettingAirplaneMode.h @@ -17,12 +17,13 @@ namespace Pinetime { SettingAirplaneMode(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingAirplaneMode() override; - void UpdateSelected(lv_obj_t* object, lv_event_t event); + void OnAirplaneModeEnabled(lv_obj_t* object, lv_event_t event); + void OnAirplaneModeDisabled(lv_obj_t* object, lv_event_t event); private: - static constexpr std::array options = {" No", " Yes"}; Controllers::Settings& settingsController; - lv_obj_t* cbOption[options.size()]; + lv_obj_t* cbEnabled; + lv_obj_t* cbDisabled; bool priorMode; }; } diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp index 7bc90b4704..981b4973a0 100644 --- a/src/displayapp/screens/settings/Settings.cpp +++ b/src/displayapp/screens/settings/Settings.cpp @@ -21,7 +21,11 @@ Settings::Settings(Pinetime::Applications::DisplayApp* app, Pinetime::Controller }, [this]() -> std::unique_ptr { return CreateScreen3(); - }}, + }, + [this]() -> std::unique_ptr { + return CreateScreen4(); + }, + }, Screens::ScreenListModes::UpDown} { } @@ -34,7 +38,6 @@ bool Settings::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } std::unique_ptr Settings::CreateScreen1() { - std::array applications {{ {Symbols::sun, "Display", Apps::SettingDisplay}, {Symbols::eye, "Wake Up", Apps::SettingWakeUp}, @@ -42,17 +45,17 @@ std::unique_ptr Settings::CreateScreen1() { {Symbols::home, "Watch face", Apps::SettingWatchFace}, }}; - return std::make_unique(0, 3, app, settingsController, applications); + return std::make_unique(0, 4, app, settingsController, applications); } std::unique_ptr Settings::CreateScreen2() { + std::array applications {{ + {Symbols::shoe, "Steps", Apps::SettingSteps}, + {Symbols::clock, "Set date", Apps::SettingSetDate}, + {Symbols::clock, "Set time", Apps::SettingSetTime}, + {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}}}; - std::array applications {{{Symbols::shoe, "Steps", Apps::SettingSteps}, - {Symbols::clock, "Set date", Apps::SettingSetDate}, - {Symbols::clock, "Set time", Apps::SettingSetTime}, - {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}}}; - - return std::make_unique(1, 3, app, settingsController, applications); + return std::make_unique(1, 4, app, settingsController, applications); } std::unique_ptr Settings::CreateScreen3() { @@ -61,8 +64,20 @@ std::unique_ptr Settings::CreateScreen3() { {Symbols::clock, "Chimes", Apps::SettingChimes}, {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, - {Symbols::list, "About", Apps::SysInfo} + {Symbols::list, "Airplane mode", Apps::SettingAirplaneMode} + }}; + + return std::make_unique(2, 4, app, settingsController, applications); +} + +std::unique_ptr Settings::CreateScreen4() { + + std::array applications {{ + {Symbols::list, "About", Apps::SysInfo}, + {Symbols::none, "None", Apps::None}, + {Symbols::none, "None", Apps::None}, + {Symbols::none, "None", Apps::None} }}; - return std::make_unique(2, 3, app, settingsController, applications); + return std::make_unique(3, 4, app, settingsController, applications); } diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 6c54cdeb03..be090075db 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -19,11 +19,12 @@ namespace Pinetime { private: Controllers::Settings& settingsController; - ScreenList<3> screens; + ScreenList<4> screens; std::unique_ptr CreateScreen1(); std::unique_ptr CreateScreen2(); std::unique_ptr CreateScreen3(); + std::unique_ptr CreateScreen4(); }; } } diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index ad13244fc4..2e3456a2fd 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -31,7 +31,7 @@ namespace Pinetime { BatteryPercentageUpdated, StartFileTransfer, StopFileTransfer, - AirplaneModeToggle + BleRadioEnableToggle }; } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 75a71ecc38..1e45fac194 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -254,7 +254,7 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning); heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp); - if (bleController.GetConnectState() == Controllers::Ble::ConnectStates::Disconnected) { + if (bleController.IsRadioEnabled() && !bleController.IsConnected()) { nimbleController.RestartFastAdv(); } @@ -440,8 +440,12 @@ void SystemTask::Work() { motorController.RunForDuration(35); displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowPairingKey); break; - case Messages::AirplaneModeToggle: - nimbleController.SwitchAirplaneMode(settingsController.GetAirplaneMode()); + case Messages::BleRadioEnableToggle: + if(settingsController.GetBleRadioEnabled()) { + nimbleController.EnableRadio(); + } else { + nimbleController.DisableRadio(); + } break; default: break; From 2803dd667f90bf8b19e45820235d3ab90490f96b Mon Sep 17 00:00:00 2001 From: avery Date: Tue, 22 Feb 2022 18:21:00 +0100 Subject: [PATCH 40/78] Use Bluetooth brand color for status text --- src/displayapp/screens/WatchFaceTerminal.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index ccfbdd0baa..c593e6bf95 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -46,7 +46,7 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, connectState = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(connectState, true); - lv_label_set_text(connectState, "[STAT]#387b54 Disconnected#"); + lv_label_set_text(connectState, "[STAT]#0082fc Disconnected#"); lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); notificationIcon = lv_label_create(lv_scr_act(), nullptr); @@ -117,12 +117,12 @@ void WatchFaceTerminal::Refresh() { bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { if(!bleRadioEnabled.Get()) { - lv_label_set_text_static(connectState, "[STAT]#387b54 Disabled#"); + lv_label_set_text_static(connectState, "[STAT]#0082fc Disabled#"); } else { if (bleState.Get()) { - lv_label_set_text_static(connectState, "[STAT]#387b54 Connected#"); + lv_label_set_text_static(connectState, "[STAT]#0082fc Connected#"); } else { - lv_label_set_text_static(connectState, "[STAT]#387b54 Disconnected#"); + lv_label_set_text_static(connectState, "[STAT]#0082fc Disconnected#"); } } } From 8dae4c82990df8236faa57ef4b6ae00c92298a1d Mon Sep 17 00:00:00 2001 From: avery Date: Tue, 22 Feb 2022 18:42:54 +0100 Subject: [PATCH 41/78] terminal: Replace notification icon with a text entry --- src/displayapp/screens/WatchFaceTerminal.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index c593e6bf95..ebd463f9d3 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -50,8 +50,9 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); - lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0); + lv_label_set_recolor(notificationIcon, true); + lv_label_set_text(notificationIcon, "[NOTI]#387b54 ---"); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, 60); label_date = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label_date, true); @@ -62,7 +63,7 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, lv_label_set_text(label_prompt_1, "user@watch:~ $ now"); label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); + lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 80); lv_label_set_text(label_prompt_2, "user@watch:~ $"); label_time = lv_label_create(lv_scr_act(), nullptr); @@ -130,9 +131,9 @@ void WatchFaceTerminal::Refresh() { notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { if (notificationState.Get()) { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true)); + lv_label_set_text_static(notificationIcon, "[NOTI]#387b54 Unread"); } else { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + lv_label_set_text_static(notificationIcon, "[NOTI]#387b54 ---"); } } From 51640c72489109149c8a7c6c7cf044862cceabf5 Mon Sep 17 00:00:00 2001 From: Arsen6331 Date: Thu, 3 Mar 2022 17:01:34 +0000 Subject: [PATCH 42/78] Add ITD as a companion app --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ae315f24bb..524f510e2f 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p - [AmazFish](https://openrepos.net/content/piggz/amazfish/) (SailfishOS) - [Siglo](https://github.com/alexr4535/siglo) (Linux) - [InfiniLink](https://github.com/xan-m/InfiniLink) **[Experimental]** (iOS) + - [ITD](https://gitea.arsenm.dev/Arsen6331/itd) (Linux) ## Development From 29f0bce46bd531ffa83f3445c0e0d893217aa50d Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 21 Feb 2022 22:50:20 +0100 Subject: [PATCH 43/78] Remove unused includes in HearRate and Motion.h The include `bits/unique_ptr.h` isn't used, so remove it. --- src/displayapp/screens/HeartRate.h | 1 - src/displayapp/screens/Motion.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/displayapp/screens/HeartRate.h b/src/displayapp/screens/HeartRate.h index baa0ccdd0a..2ad003517b 100644 --- a/src/displayapp/screens/HeartRate.h +++ b/src/displayapp/screens/HeartRate.h @@ -3,7 +3,6 @@ #include #include #include "displayapp/screens/Screen.h" -#include #include "systemtask/SystemTask.h" #include #include diff --git a/src/displayapp/screens/Motion.h b/src/displayapp/screens/Motion.h index d6997409b2..4d2bd4f2e6 100644 --- a/src/displayapp/screens/Motion.h +++ b/src/displayapp/screens/Motion.h @@ -3,7 +3,6 @@ #include #include #include "displayapp/screens/Screen.h" -#include #include #include #include From a29e30c1876891e504ad62fb35d3b1be76b175a4 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 29 Jan 2022 23:30:03 +0100 Subject: [PATCH 44/78] Notifications: replace newlines in label-copy because of const char* title The variable `title` is defined as `const char*`, which means, that `strchr()` returns a `const char*` as well according to https://www.cplusplus.com/reference/cstring/strchr/ But in the same line the return value is assigned to a non-const `char*`, which shouldn't be allowed (error with `-pedantic`). Because the `lv_label` creates an internal copy of the title sting, just modify that one instead and replace newline in the copied string. --- src/displayapp/screens/Notifications.cpp | 19 +++++++++++-------- src/displayapp/screens/Notifications.h | 4 ---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 3a39dacffe..f9afd8c71f 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -198,15 +198,18 @@ Notifications::NotificationItem::NotificationItem(const char* title, lv_obj_t* alert_type = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x888888)); - if (title == nullptr) - title = "Notification"; - char* pchar; - pchar = strchr(title, '\n'); - while (pchar != nullptr) { - *pchar = ' '; - pchar = strchr(pchar + 1, '\n'); + if(title == nullptr) { + lv_label_set_text_static(alert_type, "Notification"); + } else { + // copy title to label and replace newlines with spaces + lv_label_set_text(alert_type, title); + char *pchar = strchr(lv_label_get_text(alert_type), '\n'); + while (pchar != nullptr) { + *pchar = ' '; + pchar = strchr(pchar + 1, '\n'); + } + lv_label_refr_text(alert_type); } - lv_label_set_text(alert_type, title); lv_label_set_long_mode(alert_type, LV_LABEL_LONG_SROLL_CIRC); lv_obj_set_width(alert_type, 180); lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16); diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index f49d3b3ac1..741603567f 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -62,10 +62,6 @@ namespace Pinetime { }; private: - struct NotificationData { - const char* title; - const char* text; - }; Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::AlertNotificationService& alertNotificationService; Pinetime::Controllers::MotorController& motorController; From 1bfee61ef9f136b186199fb41abf04bf63918574 Mon Sep 17 00:00:00 2001 From: avery Date: Tue, 22 Feb 2022 17:37:28 +0100 Subject: [PATCH 45/78] Replace Airplane mode icon --- src/displayapp/screens/settings/Settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp index 981b4973a0..dce0c0714a 100644 --- a/src/displayapp/screens/settings/Settings.cpp +++ b/src/displayapp/screens/settings/Settings.cpp @@ -64,7 +64,7 @@ std::unique_ptr Settings::CreateScreen3() { {Symbols::clock, "Chimes", Apps::SettingChimes}, {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, - {Symbols::list, "Airplane mode", Apps::SettingAirplaneMode} + {Symbols::airplane, "Airplane mode", Apps::SettingAirplaneMode} }}; return std::make_unique(2, 4, app, settingsController, applications); From f1c91e1ce0fb666449e751fc4a8216f1a672f95f Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sun, 20 Feb 2022 15:06:28 +0200 Subject: [PATCH 46/78] terminal watchface: remove icons and other fixes --- src/displayapp/screens/WatchFaceTerminal.cpp | 38 +++++--------------- src/displayapp/screens/WatchFaceTerminal.h | 2 -- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index ccfbdd0baa..08a9db5b54 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -32,25 +32,15 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, motionController {motionController} { settingsController.SetClockFace(3); - batteryIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text(batteryIcon, Symbols::batteryFull); - lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, 2); - - batteryPlug = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text(batteryPlug, Symbols::plug); - lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); - 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); connectState = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(connectState, true); - lv_label_set_text(connectState, "[STAT]#387b54 Disconnected#"); lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0); label_date = lv_label_create(lv_scr_act(), nullptr); @@ -59,11 +49,11 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, label_prompt_1 = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(label_prompt_1, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -80); - lv_label_set_text(label_prompt_1, "user@watch:~ $ now"); + lv_label_set_text_static(label_prompt_1, "user@watch:~ $ now"); label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); - lv_label_set_text(label_prompt_2, "user@watch:~ $"); + lv_label_set_text_static(label_prompt_2, "user@watch:~ $"); label_time = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label_time, true); @@ -74,16 +64,14 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); lv_obj_set_size(backgroundLabel, 240, 240); lv_obj_set_pos(backgroundLabel, 0, 0); - lv_label_set_text(backgroundLabel, ""); + lv_label_set_text_static(backgroundLabel, ""); heartbeatValue = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(heartbeatValue, true); - lv_label_set_text(heartbeatValue, "[L_HR]#ee3311 0 bpm#"); lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20); stepValue = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(stepValue, true); - lv_label_set_text(stepValue, "[STEP]#ee3377 0 steps#"); lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -97,20 +85,12 @@ WatchFaceTerminal::~WatchFaceTerminal() { void WatchFaceTerminal::Refresh() { powerPresent = batteryController.IsPowerPresent(); - if (powerPresent.IsUpdated()) { - lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get())); - } - batteryPercentRemaining = batteryController.PercentRemaining(); - if (batteryPercentRemaining.IsUpdated()) { - auto batteryPercent = batteryPercentRemaining.Get(); - if (batteryPercent == 100) { - lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); - } else { - lv_obj_set_style_local_text_color(batteryIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) { + lv_label_set_text_fmt(batteryValue, "[BATT]#387b54 %d%%", batteryPercentRemaining.Get()); + if (batteryController.IsPowerPresent()) { + lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging"); } - lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); - lv_label_set_text_fmt(batteryValue, "[BATT]#387b54 %d%\%#", batteryPercent); } bleState = bleController.IsConnected(); @@ -130,9 +110,9 @@ void WatchFaceTerminal::Refresh() { notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { if (notificationState.Get()) { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true)); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(true)); } else { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); } } diff --git a/src/displayapp/screens/WatchFaceTerminal.h b/src/displayapp/screens/WatchFaceTerminal.h index 78c7b8aa82..d236da3488 100644 --- a/src/displayapp/screens/WatchFaceTerminal.h +++ b/src/displayapp/screens/WatchFaceTerminal.h @@ -60,8 +60,6 @@ namespace Pinetime { lv_obj_t* label_prompt_1; lv_obj_t* label_prompt_2; lv_obj_t* backgroundLabel; - lv_obj_t* batteryIcon; - lv_obj_t* batteryPlug; lv_obj_t* batteryValue; lv_obj_t* heartbeatValue; lv_obj_t* stepValue; From 1eaf258a633969abdd0e41fbcac9e17fe38eb409 Mon Sep 17 00:00:00 2001 From: medeyko Date: Mon, 7 Feb 2022 17:17:12 +0300 Subject: [PATCH 47/78] Update jetbrains_mono_bold_20.c Fix 0 (zero) symbol. For more details, #988 --- src/displayapp/fonts/jetbrains_mono_bold_20.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/fonts/jetbrains_mono_bold_20.c b/src/displayapp/fonts/jetbrains_mono_bold_20.c index 944e47a1dc..6cd7aead02 100644 --- a/src/displayapp/fonts/jetbrains_mono_bold_20.c +++ b/src/displayapp/fonts/jetbrains_mono_bold_20.c @@ -88,8 +88,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xe, 0x3, 0x80, 0xc0, 0x70, 0x18, 0xe, 0x0, /* U+0030 "0" */ - 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7f, - 0xdf, 0xf7, 0xe1, 0xf8, 0x7e, 0x1f, 0xcf, 0x7f, + 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7e, + 0xdf, 0xb7, 0xe1, 0xf8, 0x7e, 0x1f, 0xcf, 0x7f, 0x8f, 0xc0, /* U+0031 "1" */ From 43399b3832df7375f9139d7bd3c082a49549c616 Mon Sep 17 00:00:00 2001 From: medeyko Date: Mon, 7 Feb 2022 17:25:56 +0300 Subject: [PATCH 48/78] Update README.md --- src/displayapp/fonts/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index 40ecd3e259..5007060e79 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -31,6 +31,23 @@ Add new symbols: static constexpr const char* newSymbol = "\xEF\x86\x85"; ``` +#### Fix the zero symbol +If you don't wish the inner dot of the 0 (zero) symbol to stick to the boundary), edit `src/displayapp/fonts/jetbrains_mono_bold_20.c` and replace: + + /* U+0030 "0" */ + 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7f, + 0xdf, 0xf7, 0xe1, 0xf8, 0x7e, 0x1f, 0xcf, 0x7f, + 0x8f, 0xc0, + +with + + /* U+0030 "0" */ + 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7e, + 0xdf, 0xb7, 0xe1, 0xf8, 0x7e, 0x1f, 0xcf, 0x7f, + 0x8f, 0xc0, + +(there are two changes: 7f -> 7e and f7 -> b7) + ## Simple method to generate a font If you want to generate a basic font containing only numbers and letters, you can use the above settings but instead of specifying a range, simply list the characters you need in the Symbols field and leave the range blank. This is the approach used for the PineTimeStyle watchface. From dd28359571088cc850d315b5c3689c69f54e5838 Mon Sep 17 00:00:00 2001 From: medeyko Date: Mon, 7 Feb 2022 17:31:18 +0300 Subject: [PATCH 49/78] Update README.md remove unnecessary ) --- src/displayapp/fonts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index 5007060e79..a5f66b10e5 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -32,7 +32,7 @@ static constexpr const char* newSymbol = "\xEF\x86\x85"; ``` #### Fix the zero symbol -If you don't wish the inner dot of the 0 (zero) symbol to stick to the boundary), edit `src/displayapp/fonts/jetbrains_mono_bold_20.c` and replace: +If you don't wish the inner dot of the 0 (zero) symbol to stick to the boundary, edit `src/displayapp/fonts/jetbrains_mono_bold_20.c` and replace: /* U+0030 "0" */ 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7f, From dd47ba9782cb7a7a2268da5b493e6d385bdf08af Mon Sep 17 00:00:00 2001 From: medeyko Date: Mon, 7 Feb 2022 18:29:28 +0300 Subject: [PATCH 50/78] Update README.md More imperative tone --- src/displayapp/fonts/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index a5f66b10e5..b47376817f 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -31,8 +31,7 @@ Add new symbols: static constexpr const char* newSymbol = "\xEF\x86\x85"; ``` -#### Fix the zero symbol -If you don't wish the inner dot of the 0 (zero) symbol to stick to the boundary, edit `src/displayapp/fonts/jetbrains_mono_bold_20.c` and replace: +Then fix an error that happens during the font conversion (the inner dot of the 'zero' symbol sticks to the boundary): edit `src/displayapp/fonts/jetbrains_mono_bold_20.c` and replace: /* U+0030 "0" */ 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7f, From 5613449bfb16ed7bac672621f0f6c13afb1e1718 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Fri, 19 Nov 2021 23:14:19 +0100 Subject: [PATCH 51/78] Settings: more specific read and write mode For each filesystem interaction be more specific if we want to read from the file or write to it. Doing a non-creating read on the loading of the settings file, otherwise an empty file could be created, and when reading that empty file for the initial settings I would expect an error (or random data) when reading. --- src/components/settings/Settings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/settings/Settings.cpp b/src/components/settings/Settings.cpp index ef73ad1c6b..fee62dafce 100644 --- a/src/components/settings/Settings.cpp +++ b/src/components/settings/Settings.cpp @@ -26,7 +26,7 @@ void Settings::LoadSettingsFromFile() { SettingsData bufferSettings; lfs_file_t settingsFile; - if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDWR | LFS_O_CREAT) != LFS_ERR_OK) { + if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDONLY) != LFS_ERR_OK) { return; } fs.FileRead(&settingsFile, reinterpret_cast(&bufferSettings), sizeof(settings)); @@ -39,7 +39,7 @@ void Settings::LoadSettingsFromFile() { void Settings::SaveSettingsToFile() { lfs_file_t settingsFile; - if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_RDWR | LFS_O_CREAT) != LFS_ERR_OK) { + if ( fs.FileOpen(&settingsFile, "/settings.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { return; } fs.FileWrite(&settingsFile, reinterpret_cast(&settings), sizeof(settings)); From 30797b37bc509b24c86364f6d7b55be642a6dfb4 Mon Sep 17 00:00:00 2001 From: Yehoshua Pesach Wallach Date: Fri, 28 Jan 2022 14:34:59 +0200 Subject: [PATCH 52/78] removed SetClockFace from watchface Constructors --- src/displayapp/screens/WatchFaceAnalog.cpp | 1 - src/displayapp/screens/WatchFaceDigital.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index f027a74447..f1b9144470 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -57,7 +57,6 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, bleController {bleController}, notificationManager {notificationManager}, settingsController {settingsController} { - settingsController.SetClockFace(1); sHour = 99; sMinute = 99; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 56155d52a3..59bde83996 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -32,7 +32,6 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app, settingsController {settingsController}, heartRateController {heartRateController}, motionController {motionController} { - settingsController.SetClockFace(0); batteryIcon = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(batteryIcon, Symbols::batteryFull); From 5d974434ef2211c8feb7fe464bc9e2da3a3e1771 Mon Sep 17 00:00:00 2001 From: avery Date: Sat, 5 Mar 2022 13:01:50 +0100 Subject: [PATCH 53/78] Replace notif entry with "You have mail." text --- src/displayapp/screens/WatchFaceTerminal.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index ebd463f9d3..d1d22305bb 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -50,9 +50,7 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_recolor(notificationIcon, true); - lv_label_set_text(notificationIcon, "[NOTI]#387b54 ---"); - lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, 60); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, -100); label_date = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label_date, true); @@ -63,7 +61,7 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, lv_label_set_text(label_prompt_1, "user@watch:~ $ now"); label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 80); + lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); lv_label_set_text(label_prompt_2, "user@watch:~ $"); label_time = lv_label_create(lv_scr_act(), nullptr); @@ -131,9 +129,9 @@ void WatchFaceTerminal::Refresh() { notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { if (notificationState.Get()) { - lv_label_set_text_static(notificationIcon, "[NOTI]#387b54 Unread"); + lv_label_set_text_static(notificationIcon, "You have mail."); } else { - lv_label_set_text_static(notificationIcon, "[NOTI]#387b54 ---"); + lv_label_set_text_static(notificationIcon, ""); } } From 8844ea60b1ccb174e431f1dd96c72c5bb53c227b Mon Sep 17 00:00:00 2001 From: avery Date: Sun, 6 Mar 2022 14:01:20 +0100 Subject: [PATCH 54/78] Remove unnecessary line --- src/displayapp/screens/WatchFaceTerminal.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index e77d594b22..3a47fc5378 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -38,7 +38,6 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, connectState = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(connectState, true); - lv_label_set_text(connectState, "[STAT]#0082fc Disconnected#"); lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); notificationIcon = lv_label_create(lv_scr_act(), nullptr); From 5fe5cee9ef76fdb57810a4434517ebc6442393fb Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 20 Feb 2022 14:45:59 +0100 Subject: [PATCH 55/78] Add missing nrf_log.h includes shadowed by SystemMonitor.h Some components were missing a `nrf_log.h` include. This missing include was accidentally provided by the SystemMonitor.h header, which was included by Systemtask.h --- src/components/ble/AlertNotificationClient.cpp | 1 + src/components/ble/DfuService.cpp | 1 + src/components/ble/HeartRateService.cpp | 1 + src/components/ble/MotionService.cpp | 1 + src/components/ble/NimbleController.cpp | 1 + 5 files changed, 5 insertions(+) diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp index 0f85087494..335845e3a7 100644 --- a/src/components/ble/AlertNotificationClient.cpp +++ b/src/components/ble/AlertNotificationClient.cpp @@ -2,6 +2,7 @@ #include #include "components/ble/NotificationManager.h" #include "systemtask/SystemTask.h" +#include using namespace Pinetime::Controllers; constexpr ble_uuid16_t AlertNotificationClient::ansServiceUuid; diff --git a/src/components/ble/DfuService.cpp b/src/components/ble/DfuService.cpp index 71dcc7e637..cf99f01f82 100644 --- a/src/components/ble/DfuService.cpp +++ b/src/components/ble/DfuService.cpp @@ -3,6 +3,7 @@ #include "components/ble/BleController.h" #include "drivers/SpiNorFlash.h" #include "systemtask/SystemTask.h" +#include using namespace Pinetime::Controllers; diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp index f178af795a..4824a6b383 100644 --- a/src/components/ble/HeartRateService.cpp +++ b/src/components/ble/HeartRateService.cpp @@ -1,6 +1,7 @@ #include "components/ble/HeartRateService.h" #include "components/heartrate/HeartRateController.h" #include "systemtask/SystemTask.h" +#include using namespace Pinetime::Controllers; diff --git a/src/components/ble/MotionService.cpp b/src/components/ble/MotionService.cpp index 6381915df4..87923c2307 100644 --- a/src/components/ble/MotionService.cpp +++ b/src/components/ble/MotionService.cpp @@ -1,6 +1,7 @@ #include "components/ble/MotionService.h" #include "components/motion/MotionController.h" #include "systemtask/SystemTask.h" +#include using namespace Pinetime::Controllers; diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index f6ab626928..0be7c0f7fb 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -2,6 +2,7 @@ #include #include +#include #define min // workaround: nimble's min/max macros conflict with libstdc++ #define max #include From 187d99c0f710cf4827a026f02e41ebbd2b1271e2 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Thu, 27 Jan 2022 23:10:59 +0100 Subject: [PATCH 56/78] SystemMonitor: implement FreeRtosMonitor only if trace facility is set Split SystemMonitor into h and cpp file and move the logging code of the `Process` function into the cpp file. Depending of the `configUSE_TRACE_FACILITY` define from `src/FreeRTOSConfig.h` create either a "FreeRtosMonitor" or a "DummyMonitor". Make the `Process()` function non-const, as the FreeRtosMonitor changes the member variable `lastTick`. In `SystemTask.h` we then only need to use `SystemMonitor`, without knowledge of the `configUSE_TRACE_FACILITY` define. --- src/CMakeLists.txt | 2 ++ src/systemtask/SystemMonitor.cpp | 26 +++++++++++++++++++++ src/systemtask/SystemMonitor.h | 40 +++++--------------------------- src/systemtask/SystemTask.h | 6 +---- 4 files changed, 35 insertions(+), 39 deletions(-) create mode 100644 src/systemtask/SystemMonitor.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 025fc330b4..ff0c9b0cf8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -516,6 +516,7 @@ list(APPEND SOURCE_FILES displayapp/lv_pinetime_theme.c systemtask/SystemTask.cpp + systemtask/SystemMonitor.cpp drivers/TwiMaster.cpp heartratetask/HeartRateTask.cpp @@ -577,6 +578,7 @@ list(APPEND RECOVERY_SOURCE_FILES FreeRTOS/port_cmsis.c systemtask/SystemTask.cpp + systemtask/SystemMonitor.cpp drivers/TwiMaster.cpp components/gfx/Gfx.cpp components/rle/RleDecoder.cpp diff --git a/src/systemtask/SystemMonitor.cpp b/src/systemtask/SystemMonitor.cpp new file mode 100644 index 0000000000..90765e303b --- /dev/null +++ b/src/systemtask/SystemMonitor.cpp @@ -0,0 +1,26 @@ +#include "systemtask/SystemTask.h" +#if configUSE_TRACE_FACILITY == 1 +// FreeRtosMonitor +#include +#include +#include + +void Pinetime::System::SystemMonitor::Process() { + if (xTaskGetTickCount() - lastTick > 10000) { + NRF_LOG_INFO("---------------------------------------\nFree heap : %d", xPortGetFreeHeapSize()); + TaskStatus_t tasksStatus[10]; + auto nb = uxTaskGetSystemState(tasksStatus, 10, nullptr); + for (uint32_t i = 0; i < nb; i++) { + NRF_LOG_INFO("Task [%s] - %d", tasksStatus[i].pcTaskName, tasksStatus[i].usStackHighWaterMark); + if (tasksStatus[i].usStackHighWaterMark < 20) + NRF_LOG_INFO("WARNING!!! Task %s task is nearly full, only %dB available", + tasksStatus[i].pcTaskName, + tasksStatus[i].usStackHighWaterMark * 4); + } + lastTick = xTaskGetTickCount(); + } +} +#else +// DummyMonitor +void Pinetime::System::SystemMonitor::Process() {} +#endif diff --git a/src/systemtask/SystemMonitor.h b/src/systemtask/SystemMonitor.h index 45c02c2cf6..08c8740190 100644 --- a/src/systemtask/SystemMonitor.h +++ b/src/systemtask/SystemMonitor.h @@ -1,44 +1,16 @@ #pragma once -#include +#include // declares configUSE_TRACE_FACILITY #include -#include namespace Pinetime { namespace System { - struct DummyMonitor {}; - struct FreeRtosMonitor {}; - - template class SystemMonitor { - public: - SystemMonitor() = delete; - }; - - template <> class SystemMonitor { + class SystemMonitor { public: - void Process() const { - } - }; - - template <> class SystemMonitor { - public: - void Process() const { - if (xTaskGetTickCount() - lastTick > 10000) { - NRF_LOG_INFO("---------------------------------------\nFree heap : %d", xPortGetFreeHeapSize()); - auto nb = uxTaskGetSystemState(tasksStatus, 10, nullptr); - for (uint32_t i = 0; i < nb; i++) { - NRF_LOG_INFO("Task [%s] - %d", tasksStatus[i].pcTaskName, tasksStatus[i].usStackHighWaterMark); - if (tasksStatus[i].usStackHighWaterMark < 20) - NRF_LOG_INFO("WARNING!!! Task %s task is nearly full, only %dB available", - tasksStatus[i].pcTaskName, - tasksStatus[i].usStackHighWaterMark * 4); - } - lastTick = xTaskGetTickCount(); - } - } - + void Process(); +#if configUSE_TRACE_FACILITY == 1 private: mutable TickType_t lastTick = 0; - mutable TaskStatus_t tasksStatus[10]; +#endif }; } -} \ No newline at end of file +} diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index 517ed1ae90..c5b0379240 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -148,11 +148,7 @@ namespace Pinetime { bool stepCounterMustBeReset = false; static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000); -#if configUSE_TRACE_FACILITY == 1 - SystemMonitor monitor; -#else - SystemMonitor monitor; -#endif + SystemMonitor monitor; }; } } From 4c92ed410f89ba398b8762384bae395ff1d344c9 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Tue, 1 Feb 2022 21:48:56 +0100 Subject: [PATCH 57/78] CI: add lv_sim workflow and upload 'infinisim' executable use InfiniSim repo to build simulator in CI --- .github/workflows/lv_sim.yml | 74 ++++++++++++++++++++++++++++++++++++ README.md | 4 ++ 2 files changed, 78 insertions(+) create mode 100644 .github/workflows/lv_sim.yml diff --git a/.github/workflows/lv_sim.yml b/.github/workflows/lv_sim.yml new file mode 100644 index 0000000000..a3479f0501 --- /dev/null +++ b/.github/workflows/lv_sim.yml @@ -0,0 +1,74 @@ +# GitHub Actions Workflow to build Simulator for PineTime Smart Watch LVGL Interface + +# Name of this Workflow +name: Build PineTime LVGL Simulator + +# When to run this Workflow... +on: + + # Run on all branches + push: + branches: [] + + # Also run this Workflow when a Pull Request is created or updated in the "master" and "develop" Branch + pull_request: + branches: [ master, develop ] + +# Steps to run for the Workflow +jobs: + build: + + # Run these steps on Ubuntu + runs-on: ubuntu-latest + + steps: + + ######################################################################################### + # Download and Install Dependencies + + - name: Install cmake + uses: lukka/get-cmake@v3.18.3 + + - name: Install SDL2 development package + run: | + sudo apt-get update + sudo apt-get -y install libsdl2-dev + + ######################################################################################### + # Checkout + + - name: Checkout source files + uses: actions/checkout@v2 + with: + submodules: recursive + + ######################################################################################### + # get InfiniSim repo + + - name: Get InfiniSim repo + run: | + git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main + git -C InfiniSim submodule update --init lv_drivers + + ######################################################################################### + # CMake + + - name: CMake + run: | + cmake -G Ninja -S InfiniSim -B build_lv_sim -DInfiniTime_DIR="${PWD}" + + ######################################################################################### + # Build and Upload simulator + + # For Debugging Builds: Remove "make" option "-j" for clearer output. Add "--trace" to see details. + # For Faster Builds: Add "make" option "-j" + + - name: Build simulator executable + run: | + cmake --build build_lv_sim + + - name: Upload simulator executable + uses: actions/upload-artifact@v2 + with: + name: infinisim + path: build_lv_sim/infinisim diff --git a/README.md b/README.md index 524f510e2f..8443e43e3f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p - [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html) - [Tips on designing an app UI](doc/ui_guidelines.md) +### InfiniSim Simulator +Use the [InfiniSim Simulator](https://github.com/InfiniTimeOrg/InfiniSim) to experience the `InfiniTime` user interface directly on your PC, to shorten the time until you get your hands on a real [PineTime smartwatch](https://www.pine64.org/pinetime/). +Or use it to develop new Watchfaces, new Screens, or quickly iterate on the user interface. + ### Contributing - [How to contribute?](/doc/contribute.md) - [Coding conventions](/doc/coding-convention.md) From 204ad7ca2a8bf30caee7bc9b7395001c0d720b10 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sun, 27 Feb 2022 14:30:47 +0200 Subject: [PATCH 58/78] Update font readme, update fonts, add missing files --- src/displayapp/fonts/JetBrainsMono-Bold.ttf | Bin 173264 -> 210128 bytes .../fonts/JetBrainsMono-Regular.ttf | Bin 0 -> 203952 bytes src/displayapp/fonts/README.md | 58 +-- src/displayapp/fonts/jetbrains_mono_42.c | 20 +- src/displayapp/fonts/jetbrains_mono_76.c | 44 +-- src/displayapp/fonts/jetbrains_mono_bold_20.c | 362 +++++++++--------- src/displayapp/fonts/open_sans_light.c | 2 +- 7 files changed, 248 insertions(+), 238 deletions(-) create mode 100644 src/displayapp/fonts/JetBrainsMono-Regular.ttf diff --git a/src/displayapp/fonts/JetBrainsMono-Bold.ttf b/src/displayapp/fonts/JetBrainsMono-Bold.ttf index 0cd1cb66bd193f2b178d0a69a7b0658d76b3a670..0a9280916cef9ef3e0a8061c26834409b27e5fcb 100644 GIT binary patch delta 84890 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
lulm(T7M!5Ubwkm%AZ>vs^8F#mLco1*^#c!d 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 LJjYC}i6HpD?0Ry4 delta 49295 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 diff --git a/src/displayapp/fonts/JetBrainsMono-Regular.ttf b/src/displayapp/fonts/JetBrainsMono-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8da8aa405130e21ec0ed889de44b43ef51bea914 GIT binary patch literal 203952 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 literal 0 HcmV?d00001 diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index b47376817f..c8fb0d35b8 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -7,20 +7,12 @@ ## Generate the fonts: * Open the [LVGL font converter](https://lvgl.io/tools/fontconverter) -* Name : jetbrains_mono_bold_20 -* Size : 20 -* Bpp : 1 bit-per-pixel -* Do not enable font compression and horizontal subpixel hinting -* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7f, 0x410-0x44f` -* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following - range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf072` -* Click on Convert, and download the file `jetbrains_mono_bold_20.c` and copy it in `src/DisplayApp/Fonts` -* Add the font .c file path to src/CMakeLists.txt -* Add an LV_FONT_DECLARE line in src/libs/lv_conf.h +* Enter the settings for the font that you wish to convert +* Click on Convert, download the file and place it in `src/DisplayApp/Fonts` -Add new symbols: +### How to add new symbols: -* Browse the [cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and find your new symbols +* Browse [this cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and pick symbols * For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list (Remember to keep this readme updated with newest range list) * Convert this hex value into a UTF-8 code @@ -31,7 +23,18 @@ Add new symbols: static constexpr const char* newSymbol = "\xEF\x86\x85"; ``` -Then fix an error that happens during the font conversion (the inner dot of the 'zero' symbol sticks to the boundary): edit `src/displayapp/fonts/jetbrains_mono_bold_20.c` and replace: +### Small font + +* Name: jetbrains_mono_bold_20 +* Size: 20 +* Bpp: 1 bit-per-pixel +* Do not enable font compression or horizontal subpixel rendering +* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7e, 0x410-0x44f` +* Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following + range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf072` +* Fix an error in the font conversion. + +Replace the following: /* U+0030 "0" */ 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xf8, 0x7f, @@ -47,25 +50,34 @@ with (there are two changes: 7f -> 7e and f7 -> b7) -## Simple method to generate a font -If you want to generate a basic font containing only numbers and letters, you can use the above settings but instead of specifying a range, simply list the characters you need in the Symbols field and leave the range blank. This is the approach used for the PineTimeStyle watchface. -This works well for fonts which will only be used to display numbers, but will fail if you try to add a colon or other punctuation. +### Medium font + +* Name: jetbrains_mono_42 +* Size: 42 +* Bpp: 1 bit-per-pixel +* Do not enable font compression or horizontal subpixel rendering +* Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x25, 0x30-0x3a` + +### Large font +* Name: jetbrains_mono_76 +* Size: 76 +* Bpp: 1 bit-per-pixel +* Do not enable font compression or horizontal subpixel rendering +* Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x25, 0x2D, 0x2F, 0x30-0x3a` + +### PineTimeStyle font -* Open the [LVGL font converter](https://lvgl.io/tools/fontconverter) * Name : open_sans_light * Size : 150 * Bpp : 1 bit-per-pixel -* Do not enable font compression and horizontal subpixel hinting +* Do not enable font compression or horizontal subpixel rendering * Load the file `open_sans_light.tff` (use the file in this repo to ensure the version matches) and specify the following symbols : `0123456789` -* Click on Convert, and download the file `open_sans_light.c` and copy it in `src/DisplayApp/Fonts` -* Add the font .c file path to src/CMakeLists.txt (search for jetbrains to find the appropriate location/format) -* Add an LV_FONT_DECLARE line in src/libs/lv_conf.h (as above) #### Navigation font To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app) -this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and creat a ttf file the +this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and create a ttf file the project for the site is *lv_font_navi_80.json* you can import it to add or remove icons You can also use the online LVGL tool to create the .c @@ -74,5 +86,3 @@ ttf file : navigation.ttf name : lv_font_navi_80 size : 80px Bpp : 2 bit-per-pix $lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 --no-prefilter -o lv_font_navi_80.c - -#### I use the method above to create the other ttf diff --git a/src/displayapp/fonts/jetbrains_mono_42.c b/src/displayapp/fonts/jetbrains_mono_42.c index 6f25f5abe6..b5218b952a 100644 --- a/src/displayapp/fonts/jetbrains_mono_42.c +++ b/src/displayapp/fonts/jetbrains_mono_42.c @@ -61,13 +61,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xff, 0xf8, /* U+0032 "2" */ - 0x3, 0xf8, 0x1, 0xff, 0xc0, 0x7f, 0xfe, 0x1f, - 0x7, 0xc7, 0xc0, 0x3c, 0xf0, 0x7, 0xbc, 0x0, + 0x3, 0xf8, 0x1, 0xff, 0xc0, 0xff, 0xfc, 0x1f, + 0x7, 0xc7, 0xc0, 0x7c, 0xf0, 0x7, 0xbc, 0x0, 0x7f, 0x80, 0xf, 0xf0, 0x1, 0xe0, 0x0, 0x3c, 0x0, 0x7, 0x80, 0x1, 0xf0, 0x0, 0x3c, 0x0, 0xf, 0x80, 0x1, 0xe0, 0x0, 0x7c, 0x0, 0x1f, - 0x0, 0x7, 0xc0, 0x1, 0xf0, 0x0, 0x7e, 0x0, - 0xf, 0x80, 0x3, 0xe0, 0x0, 0xf8, 0x0, 0x3e, + 0x0, 0x7, 0xc0, 0x1, 0xf0, 0x0, 0x7c, 0x0, + 0x1f, 0x0, 0x3, 0xc0, 0x0, 0xf0, 0x0, 0x3e, 0x0, 0xf, 0x80, 0x3, 0xe0, 0x0, 0xf8, 0x0, 0x3e, 0x0, 0x7, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xff, 0xf8, @@ -75,12 +75,12 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { /* U+0033 "3" */ 0x7f, 0xff, 0x8f, 0xff, 0xf1, 0xff, 0xfe, 0x0, 0x3, 0xc0, 0x0, 0xf0, 0x0, 0x3c, 0x0, 0xf, - 0x0, 0x3, 0xc0, 0x0, 0xf0, 0x0, 0x3e, 0x0, - 0x7, 0x80, 0x1, 0xfe, 0x0, 0x3f, 0xf0, 0x7, - 0xff, 0x0, 0x3, 0xf0, 0x0, 0x1e, 0x0, 0x3, - 0xc0, 0x0, 0x3c, 0x0, 0x7, 0x80, 0x0, 0xf0, + 0x0, 0x3, 0xe0, 0x0, 0x78, 0x0, 0x1e, 0x0, + 0x7, 0x80, 0x1, 0xfc, 0x0, 0x3f, 0xe0, 0x7, + 0xfe, 0x0, 0xff, 0xe0, 0x0, 0x3e, 0x0, 0x3, + 0xc0, 0x0, 0x7c, 0x0, 0x7, 0x80, 0x0, 0xf0, 0x0, 0x1e, 0x0, 0x3, 0xfc, 0x0, 0x7f, 0x80, - 0xf, 0xf0, 0x1, 0xef, 0x0, 0x79, 0xf0, 0x1f, + 0xf, 0xf0, 0x1, 0xff, 0x0, 0x79, 0xe0, 0x1f, 0x1f, 0x7, 0xc3, 0xff, 0xf0, 0x1f, 0xfc, 0x0, 0xfe, 0x0, @@ -245,7 +245,7 @@ lv_font_t jetbrains_mono_42 = { #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, #endif -#if LV_VERSION_CHECK(7, 4, 0) +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 .underline_position = -7, .underline_thickness = 2, #endif diff --git a/src/displayapp/fonts/jetbrains_mono_76.c b/src/displayapp/fonts/jetbrains_mono_76.c index 9c92e14471..2200e393ec 100644 --- a/src/displayapp/fonts/jetbrains_mono_76.c +++ b/src/displayapp/fonts/jetbrains_mono_76.c @@ -175,30 +175,30 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* U+0032 "2" */ - 0x0, 0x7, 0xfc, 0x0, 0x0, 0x1f, 0xff, 0xe0, + 0x0, 0xf, 0xfc, 0x0, 0x0, 0x1f, 0xff, 0xe0, 0x0, 0x1f, 0xff, 0xfe, 0x0, 0xf, 0xff, 0xff, - 0xe0, 0x7, 0xff, 0xff, 0xfc, 0x3, 0xff, 0xff, - 0xff, 0x81, 0xff, 0xc0, 0x7f, 0xe0, 0xff, 0x80, + 0xc0, 0x7, 0xff, 0xff, 0xf8, 0x3, 0xff, 0xff, + 0xff, 0x1, 0xff, 0xc0, 0x7f, 0xe0, 0xff, 0x80, 0x7, 0xfc, 0x3f, 0xc0, 0x0, 0xff, 0x1f, 0xe0, 0x0, 0x1f, 0xe7, 0xf0, 0x0, 0x3, 0xf9, 0xfc, - 0x0, 0x0, 0xfe, 0xff, 0x0, 0x0, 0x1f, 0xff, + 0x0, 0x0, 0xfe, 0xff, 0x0, 0x0, 0x3f, 0xff, 0x80, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x1, 0xff, 0xf8, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x1, 0xfc, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, - 0x7, 0xf8, 0x0, 0x0, 0x1, 0xfe, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x0, + 0x3f, 0x80, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, + 0x7, 0xf8, 0x0, 0x0, 0x1, 0xfc, 0x0, 0x0, + 0x0, 0xff, 0x0, 0x0, 0x0, 0x3f, 0x80, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x7, 0xfc, 0x0, 0x0, 0x3, 0xfe, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x7f, 0xc0, - 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x1f, 0xf0, + 0x0, 0x7, 0xf8, 0x0, 0x0, 0x3, 0xfe, 0x0, + 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, 0xff, 0x80, + 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, 0xff, 0x80, 0x0, 0x0, 0x7f, 0xc0, 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x1f, - 0xf8, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x0, 0x7, - 0xfe, 0x0, 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, + 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x7, + 0xfc, 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, 0xff, 0x80, 0x0, 0x0, 0x7f, 0xc0, 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x1f, 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x7, 0xfc, 0x0, 0x0, @@ -214,22 +214,22 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xff, 0x80, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0x1, 0xfc, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, - 0x0, 0x7f, 0x80, 0x0, 0x0, 0x1f, 0xc0, 0x0, - 0x0, 0xf, 0xe0, 0x0, 0x0, 0x7, 0xf0, 0x0, + 0x0, 0x7f, 0x80, 0x0, 0x0, 0x3f, 0xc0, 0x0, + 0x0, 0x1f, 0xe0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0x1, 0xfc, 0x0, - 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x7f, 0x80, + 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x7f, 0x80, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x1f, 0xe0, - 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x1, 0xff, + 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x1, 0xff, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0xc0, 0x0, 0x1f, 0xff, 0xf8, 0x0, 0x7, 0xff, 0xff, 0x0, 0x1, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x1f, 0xfc, 0x0, - 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xe0, + 0xff, 0xff, 0xe0, 0x0, 0x0, 0xf, 0xfc, 0x0, + 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x1, 0xfc, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x1, 0xfc, 0x0, 0x0, - 0x0, 0x7f, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x80, + 0x0, 0x7f, 0xfe, 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x1, 0xff, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x3f, 0xdf, 0xc0, 0x0, 0xf, 0xe7, 0xf8, 0x0, 0x7, 0xf9, @@ -466,10 +466,10 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 878, .adv_w = 730, .box_w = 34, .box_h = 56, .ofs_x = 7, .ofs_y = 0}, {.bitmap_index = 1116, .adv_w = 730, .box_w = 34, .box_h = 57, .ofs_x = 6, .ofs_y = 0}, {.bitmap_index = 1359, .adv_w = 730, .box_w = 34, .box_h = 57, .ofs_x = 5, .ofs_y = -1}, - {.bitmap_index = 1602, .adv_w = 730, .box_w = 32, .box_h = 56, .ofs_x = 6, .ofs_y = 0}, + {.bitmap_index = 1602, .adv_w = 730, .box_w = 32, .box_h = 56, .ofs_x = 5, .ofs_y = 0}, {.bitmap_index = 1826, .adv_w = 730, .box_w = 32, .box_h = 57, .ofs_x = 7, .ofs_y = -1}, {.bitmap_index = 2054, .adv_w = 730, .box_w = 36, .box_h = 58, .ofs_x = 5, .ofs_y = -1}, - {.bitmap_index = 2315, .adv_w = 730, .box_w = 36, .box_h = 56, .ofs_x = 5, .ofs_y = 0}, + {.bitmap_index = 2315, .adv_w = 730, .box_w = 36, .box_h = 56, .ofs_x = 6, .ofs_y = 0}, {.bitmap_index = 2567, .adv_w = 730, .box_w = 36, .box_h = 58, .ofs_x = 5, .ofs_y = -1}, {.bitmap_index = 2828, .adv_w = 730, .box_w = 36, .box_h = 57, .ofs_x = 5, .ofs_y = 0}, {.bitmap_index = 3085, .adv_w = 730, .box_w = 13, .box_h = 44, .ofs_x = 16, .ofs_y = -1} @@ -541,7 +541,7 @@ lv_font_t jetbrains_mono_76 = { #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, #endif -#if LV_VERSION_CHECK(7, 4, 0) +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 .underline_position = -12, .underline_thickness = 4, #endif diff --git a/src/displayapp/fonts/jetbrains_mono_bold_20.c b/src/displayapp/fonts/jetbrains_mono_bold_20.c index 6cd7aead02..cc67532a32 100644 --- a/src/displayapp/fonts/jetbrains_mono_bold_20.c +++ b/src/displayapp/fonts/jetbrains_mono_bold_20.c @@ -32,9 +32,9 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xef, 0xdf, 0xbf, 0x7e, 0xfd, 0xc0, /* U+0023 "#" */ - 0x8, 0xc3, 0x10, 0x66, 0x3f, 0xf7, 0xfe, 0x23, - 0x4, 0x61, 0x88, 0x31, 0x1f, 0xfb, 0xff, 0x19, - 0x82, 0x30, 0xc4, 0x0, + 0x8, 0xc3, 0x18, 0x62, 0x3f, 0xf7, 0xfe, 0x23, + 0xc, 0x61, 0x88, 0xff, 0xdf, 0xf8, 0x8c, 0x11, + 0x86, 0x30, 0xc4, 0x0, /* U+0024 "$" */ 0x8, 0x2, 0x0, 0x81, 0xfc, 0x7f, 0xba, 0x7e, @@ -93,11 +93,11 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x8f, 0xc0, /* U+0031 "1" */ - 0x1e, 0x3f, 0x3b, 0x99, 0xc8, 0xe0, 0x70, 0x38, + 0x1e, 0x3f, 0x3f, 0x99, 0xc8, 0xe0, 0x70, 0x38, 0x1c, 0xe, 0x7, 0x3, 0x81, 0xcf, 0xff, 0xfc, /* U+0032 "2" */ - 0x3e, 0x3f, 0xbc, 0xfc, 0x70, 0x38, 0x1c, 0x1c, + 0x3e, 0x3f, 0xbd, 0xfc, 0x70, 0x38, 0x1c, 0x1c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0xf, 0xff, 0xfc, /* U+0033 "3" */ @@ -122,7 +122,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { /* U+0037 "7" */ 0xff, 0xff, 0xfe, 0x1f, 0x86, 0x3, 0x80, 0xe0, 0x30, 0x1c, 0x6, 0x3, 0x80, 0xc0, 0x70, 0x1c, - 0x6, 0x0, + 0xe, 0x0, /* U+0038 "8" */ 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe1, 0xdc, 0xe3, @@ -157,7 +157,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x30, 0x30, 0x0, 0x0, 0x70, 0x70, /* U+0040 "@" */ - 0x1f, 0x7, 0xf9, 0xc3, 0x70, 0x3c, 0x7, 0x8f, + 0x1f, 0x7, 0xf9, 0xc3, 0x70, 0x3c, 0x7, 0x8e, 0xf3, 0xfe, 0x63, 0xcc, 0x79, 0x8f, 0x31, 0xe6, 0x3c, 0xff, 0x8e, 0xf8, 0x3, 0x80, 0x3e, 0x3, 0xc0, @@ -168,8 +168,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xf0, 0x30, /* U+0042 "B" */ - 0xfe, 0x3f, 0xce, 0x3b, 0x8e, 0xe3, 0xb8, 0xcf, - 0xe3, 0xfc, 0xe3, 0xb8, 0x7e, 0x1f, 0x8f, 0xff, + 0xfe, 0x3f, 0xce, 0x3b, 0x8e, 0xe3, 0xb8, 0xef, + 0xe3, 0xfc, 0xe3, 0xf8, 0x7e, 0x1f, 0x8f, 0xff, 0xbf, 0xc0, /* U+0043 "C" */ @@ -217,9 +217,9 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0xf, 0xff, 0xfc, /* U+004D "M" */ - 0xe1, 0xf8, 0x7f, 0x3f, 0xcf, 0xd2, 0xf7, 0xbd, - 0xef, 0x33, 0xc0, 0xf0, 0x3c, 0xf, 0x3, 0xc0, - 0xf0, 0x30, + 0xf3, 0xfc, 0xfd, 0x3f, 0xcf, 0xff, 0xff, 0xfe, + 0xdf, 0xb7, 0xe1, 0xf8, 0x7e, 0x1f, 0x87, 0xe1, + 0xf8, 0x70, /* U+004E "N" */ 0xe1, 0xf0, 0xfc, 0x7e, 0x3f, 0x9e, 0xcf, 0x67, @@ -245,7 +245,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xb8, 0x70, /* U+0053 "S" */ - 0x3f, 0x1f, 0xee, 0x3f, 0x87, 0xe0, 0x3c, 0x7, + 0x3f, 0x1f, 0xee, 0x3f, 0x87, 0xe0, 0x3e, 0x7, 0xf0, 0xfe, 0x3, 0xc0, 0x7e, 0x1f, 0xcf, 0x7f, 0x8f, 0xc0, @@ -260,7 +260,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { /* U+0056 "V" */ 0xc0, 0xf8, 0x7e, 0x1d, 0x86, 0x61, 0x9c, 0xe7, - 0x38, 0xcc, 0x33, 0xf, 0xc3, 0xf0, 0x78, 0x1e, + 0x38, 0xcc, 0x33, 0xe, 0xc3, 0xf0, 0x78, 0x1e, 0x7, 0x80, /* U+0057 "W" */ @@ -314,8 +314,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xc7, 0xe3, 0xf1, 0xf8, 0xfc, 0x7f, 0xf7, 0x70, /* U+0063 "c" */ - 0x3e, 0x3f, 0xb8, 0xfc, 0x7e, 0x7, 0x3, 0x81, - 0xc7, 0xe3, 0xbf, 0x8f, 0x80, + 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe0, 0x38, 0xe, + 0x3, 0x87, 0xf3, 0xdf, 0xe3, 0xf0, /* U+0064 "d" */ 0x3, 0x81, 0xc0, 0xe7, 0x77, 0xff, 0x1f, 0x8f, @@ -382,12 +382,12 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xe, /* U+0072 "r" */ - 0xee, 0x7f, 0xb9, 0xfc, 0x7e, 0x3f, 0x3, 0x81, + 0xee, 0x7f, 0xb8, 0xfc, 0x7e, 0x3f, 0x3, 0x81, 0xc0, 0xe0, 0x70, 0x38, 0x0, /* U+0073 "s" */ 0x1f, 0x1f, 0xf7, 0x1d, 0xc0, 0x7c, 0xf, 0xe0, - 0x3c, 0x7, 0x71, 0xdf, 0xe3, 0xf0, + 0x3c, 0x7, 0x71, 0xdf, 0xf3, 0xf0, /* U+0074 "t" */ 0x1c, 0x7, 0x1, 0xc3, 0xff, 0xff, 0xc7, 0x1, @@ -399,12 +399,12 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xc7, 0xe3, 0xbf, 0x8f, 0x80, /* U+0076 "v" */ - 0xe0, 0xf8, 0x76, 0x19, 0x86, 0x73, 0x8c, 0xc3, + 0xc0, 0xf8, 0x7e, 0x1d, 0x86, 0x73, 0x8c, 0xc3, 0x30, 0xfc, 0x1e, 0x7, 0x81, 0xe0, /* U+0077 "w" */ - 0xe6, 0x36, 0x66, 0x66, 0x66, 0xf6, 0x6f, 0x66, - 0x96, 0x69, 0x62, 0x94, 0x39, 0xc3, 0x9c, 0x39, + 0xc6, 0x36, 0x66, 0x66, 0x66, 0xf6, 0x6f, 0x66, + 0x96, 0x69, 0x62, 0x94, 0x29, 0x43, 0x9c, 0x39, 0xc0, /* U+0078 "x" */ @@ -412,7 +412,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xe0, 0xfc, 0x73, 0x9c, 0xee, 0x1c, /* U+0079 "y" */ - 0xe1, 0xf8, 0x76, 0x19, 0xce, 0x73, 0x8c, 0xc3, + 0xe0, 0xf8, 0x76, 0x19, 0xce, 0x73, 0x8c, 0xc3, 0xf0, 0x7c, 0x1e, 0x7, 0x80, 0xe0, 0x30, 0x1c, 0x6, 0x3, 0x80, @@ -421,17 +421,17 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xe0, 0xe0, 0x7f, 0xff, 0xe0, /* U+007B "{" */ - 0x3, 0x87, 0xc3, 0x81, 0xc0, 0xe0, 0x70, 0x38, + 0x7, 0x87, 0xc3, 0x81, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0xfc, 0x7e, 0x3, 0x81, 0xc0, 0xe0, 0x70, - 0x38, 0x1c, 0xf, 0x81, 0xc0, + 0x30, 0x1c, 0xf, 0x83, 0xc0, /* U+007C "|" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, /* U+007D "}" */ - 0xf0, 0x3e, 0x1, 0xc0, 0x70, 0x1c, 0x7, 0x1, - 0xc0, 0x70, 0xf, 0xc3, 0xf1, 0xc0, 0x70, 0x1c, - 0x7, 0x1, 0xc0, 0x70, 0xf8, 0x3c, 0x0, + 0xf0, 0x7c, 0xe, 0x7, 0x3, 0x81, 0xc0, 0xe0, + 0x70, 0x1f, 0x8f, 0xce, 0x7, 0x3, 0x81, 0xc0, + 0x60, 0x70, 0xf8, 0x78, 0x0, /* U+007E "~" */ 0x78, 0xff, 0x3c, 0xcf, 0x3f, 0xc7, 0x80, @@ -447,8 +447,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xbf, 0xc0, /* U+0412 "В" */ - 0xfe, 0x3f, 0xce, 0x3b, 0x8e, 0xe3, 0xb8, 0xcf, - 0xe3, 0xfc, 0xe3, 0xb8, 0x7e, 0x1f, 0x8f, 0xff, + 0xfe, 0x3f, 0xce, 0x3b, 0x8e, 0xe3, 0xb8, 0xef, + 0xe3, 0xfc, 0xe3, 0xf8, 0x7e, 0x1f, 0x8f, 0xff, 0xbf, 0xc0, /* U+0413 "Г" */ @@ -470,9 +470,9 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x66, 0x66, 0x66, 0x6c, 0x63, /* U+0417 "З" */ - 0x1f, 0xf, 0xf3, 0xc7, 0x0, 0x60, 0x1c, 0x1e, - 0x3, 0xf0, 0xe, 0x0, 0xe0, 0x1f, 0x83, 0xf8, - 0xf7, 0xfc, 0x3e, 0x0, + 0x3f, 0x1f, 0xef, 0x1f, 0x87, 0x1, 0xc7, 0xc1, + 0xf8, 0xf, 0x1, 0xc0, 0x7e, 0x1f, 0xcf, 0x7f, + 0x8f, 0x80, /* U+0418 "И" */ 0xc3, 0xe3, 0xf1, 0xf8, 0xfc, 0xde, 0x6f, 0x37, @@ -494,9 +494,9 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xf8, 0x70, /* U+041C "М" */ - 0xe1, 0xf8, 0x7f, 0x3f, 0xcf, 0xd2, 0xf7, 0xbd, - 0xef, 0x33, 0xc0, 0xf0, 0x3c, 0xf, 0x3, 0xc0, - 0xf0, 0x30, + 0xf3, 0xfc, 0xfd, 0x3f, 0xcf, 0xff, 0xff, 0xfe, + 0xdf, 0xb7, 0xe1, 0xf8, 0x7e, 0x1f, 0x87, 0xe1, + 0xf8, 0x70, /* U+041D "Н" */ 0xe3, 0xf1, 0xf8, 0xfc, 0x7e, 0x3f, 0x1f, 0xff, @@ -546,7 +546,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xff, 0xf0, 0x1c, 0x7, 0x1, 0xc0, /* U+0427 "Ч" */ - 0xe3, 0xf1, 0xf8, 0xfc, 0x7e, 0x3f, 0x1f, 0xce, + 0xe3, 0xf1, 0xf8, 0xfc, 0x7e, 0x3f, 0x1f, 0x8f, 0xff, 0x3f, 0x81, 0xc0, 0xe0, 0x70, 0x38, 0x1c, /* U+0428 "Ш" */ @@ -593,8 +593,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x1f, 0x87, 0xe3, 0xff, 0xf3, 0xdc, /* U+0431 "б" */ - 0x1f, 0x3f, 0x9c, 0x1c, 0xe, 0xe7, 0xfb, 0x8f, - 0xc7, 0xe3, 0xf1, 0xf8, 0xfc, 0x77, 0xf1, 0xf0, + 0x1f, 0x3f, 0x9c, 0x1c, 0xe, 0xe7, 0xfb, 0x9f, + 0xc7, 0xe3, 0xf1, 0xf8, 0xfe, 0xf7, 0xf1, 0xf0, /* U+0432 "в" */ 0xff, 0x3f, 0xee, 0x3b, 0x8e, 0xfe, 0x3f, 0xee, @@ -619,7 +619,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x70, /* U+0437 "з" */ - 0x3f, 0x1f, 0xfe, 0x1c, 0x7, 0x1f, 0x87, 0xe0, + 0x3f, 0x1f, 0xfe, 0x1c, 0x7, 0x1f, 0x7, 0xe0, 0x1c, 0x7, 0xe1, 0xdf, 0xe3, 0xf0, /* U+0438 "и" */ @@ -632,8 +632,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xc7, 0xc3, /* U+043A "к" */ - 0xe1, 0xf8, 0xee, 0x33, 0x9c, 0xfe, 0x3f, 0x8e, - 0x73, 0x9c, 0xe3, 0xb8, 0x6e, 0x1c, + 0xe1, 0xf8, 0xee, 0x3b, 0x9c, 0xfe, 0x3f, 0x8e, + 0x73, 0x8c, 0xe3, 0xb8, 0x6e, 0x1c, /* U+043B "л" */ 0x3f, 0xcf, 0xf3, 0x9c, 0xe7, 0x39, 0xce, 0x73, @@ -644,7 +644,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xef, 0x33, 0xc0, 0xf0, 0x3c, 0xc, /* U+043D "н" */ - 0xe3, 0xf1, 0xf8, 0xfc, 0x7e, 0x3f, 0xff, 0xff, + 0xe3, 0xf1, 0xf8, 0xfc, 0x7f, 0xff, 0xff, 0x8f, 0xc7, 0xe3, 0xf1, 0xf8, 0xe0, /* U+043E "о" */ @@ -661,15 +661,15 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x80, /* U+0441 "с" */ - 0x3e, 0x3f, 0xb8, 0xfc, 0x7e, 0x7, 0x3, 0x81, - 0xc7, 0xe3, 0xbf, 0x8f, 0x80, + 0x3f, 0x1f, 0xef, 0x3f, 0x87, 0xe0, 0x38, 0xe, + 0x3, 0x87, 0xf3, 0xdf, 0xe3, 0xf0, /* U+0442 "т" */ 0xff, 0xff, 0xf0, 0xe0, 0x38, 0xe, 0x3, 0x80, 0xe0, 0x38, 0xe, 0x3, 0x80, 0xe0, /* U+0443 "у" */ - 0xe1, 0xf8, 0x76, 0x19, 0xce, 0x73, 0x8c, 0xc3, + 0xe0, 0xf8, 0x76, 0x19, 0xce, 0x73, 0x8c, 0xc3, 0xf0, 0x7c, 0x1e, 0x7, 0x80, 0xe0, 0x30, 0x1c, 0x6, 0x3, 0x80, @@ -688,7 +688,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xc0, 0x70, /* U+0447 "ч" */ - 0xe3, 0xf1, 0xf8, 0xfc, 0x7e, 0x3b, 0xfc, 0xfe, + 0xe3, 0xf1, 0xf8, 0xfc, 0x7e, 0x3f, 0xfd, 0xfe, 0x7, 0x3, 0x81, 0xc0, 0xe0, /* U+0448 "ш" */ @@ -714,8 +714,8 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0x1f, 0x87, 0xe1, 0xff, 0xef, 0xf0, /* U+044D "э" */ - 0x3e, 0x3f, 0xb8, 0xe0, 0x70, 0xf8, 0x7c, 0xf, - 0xc7, 0xe7, 0xbf, 0x8f, 0x80, + 0x1f, 0x1f, 0xe6, 0x3c, 0x7, 0xf, 0xc3, 0xf0, + 0x1d, 0x87, 0x73, 0xdf, 0xe1, 0xf0, /* U+044E "ю" */ 0xc7, 0xb3, 0xfc, 0xcf, 0x33, 0xfc, 0xff, 0x3c, @@ -1123,139 +1123,139 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 975, .adv_w = 192, .box_w = 5, .box_h = 3, .ofs_x = 3, .ofs_y = 13}, {.bitmap_index = 977, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, {.bitmap_index = 991, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1007, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1020, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1036, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1049, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1067, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, - {.bitmap_index = 1084, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1100, .adv_w = 192, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1120, .adv_w = 192, .box_w = 8, .box_h = 19, .ofs_x = 1, .ofs_y = -4}, - {.bitmap_index = 1139, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1157, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1177, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1191, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1204, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1217, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 2, .ofs_y = -4}, - {.bitmap_index = 1234, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, - {.bitmap_index = 1251, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1264, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1278, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1296, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1309, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1323, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1340, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1354, .adv_w = 192, .box_w = 10, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, - {.bitmap_index = 1373, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1386, .adv_w = 192, .box_w = 9, .box_h = 18, .ofs_x = 2, .ofs_y = -2}, - {.bitmap_index = 1407, .adv_w = 192, .box_w = 3, .box_h = 18, .ofs_x = 5, .ofs_y = -2}, - {.bitmap_index = 1414, .adv_w = 192, .box_w = 10, .box_h = 18, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 1437, .adv_w = 192, .box_w = 10, .box_h = 5, .ofs_x = 1, .ofs_y = 5}, - {.bitmap_index = 1444, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1462, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1480, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1498, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1514, .adv_w = 192, .box_w = 11, .box_h = 17, .ofs_x = 1, .ofs_y = -3}, - {.bitmap_index = 1538, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1554, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1575, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1595, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1611, .adv_w = 192, .box_w = 9, .box_h = 19, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1633, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1651, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1669, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1687, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1703, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1719, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1735, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1753, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1771, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1789, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1807, .adv_w = 192, .box_w = 10, .box_h = 16, .ofs_x = 1, .ofs_y = -1}, - {.bitmap_index = 1827, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1845, .adv_w = 192, .box_w = 10, .box_h = 17, .ofs_x = 2, .ofs_y = -3}, - {.bitmap_index = 1867, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1883, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1901, .adv_w = 192, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 1923, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1944, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1962, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 1980, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 1996, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2014, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2032, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2046, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2062, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2076, .adv_w = 192, .box_w = 8, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2087, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = -3}, - {.bitmap_index = 2107, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2120, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 2137, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2151, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2164, .adv_w = 192, .box_w = 9, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2182, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2196, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2210, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2224, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2237, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2250, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2263, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 2, .ofs_y = -4}, - {.bitmap_index = 2280, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2293, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2307, .adv_w = 192, .box_w = 10, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, - {.bitmap_index = 2326, .adv_w = 192, .box_w = 10, .box_h = 18, .ofs_x = 1, .ofs_y = -4}, - {.bitmap_index = 2349, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2363, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = -3}, - {.bitmap_index = 2381, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2394, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2408, .adv_w = 192, .box_w = 11, .box_h = 13, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 2426, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 2443, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2457, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, - {.bitmap_index = 2471, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2484, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2498, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 2511, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2561, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2610, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2658, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2708, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 2737, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 2792, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2831, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2874, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, - {.bitmap_index = 2902, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 2950, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 2989, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3028, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, - {.bitmap_index = 3056, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3104, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 3148, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3209, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3262, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3281, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3331, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3367, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3415, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 3455, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3498, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3536, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3574, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3612, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3650, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3688, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3724, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, - {.bitmap_index = 3762, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3791, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 3829, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3895, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3944, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3994, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4054, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 4107, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 4168, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4223, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4276, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} + {.bitmap_index = 1007, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1021, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1037, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1050, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1068, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 1085, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1101, .adv_w = 192, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1121, .adv_w = 192, .box_w = 8, .box_h = 19, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 1140, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1158, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1178, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1192, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1205, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1218, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 1235, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 1252, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1265, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1279, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1297, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1310, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1324, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1341, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1355, .adv_w = 192, .box_w = 10, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 1374, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1387, .adv_w = 192, .box_w = 9, .box_h = 18, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 1408, .adv_w = 192, .box_w = 3, .box_h = 18, .ofs_x = 5, .ofs_y = -2}, + {.bitmap_index = 1415, .adv_w = 192, .box_w = 9, .box_h = 18, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 1436, .adv_w = 192, .box_w = 10, .box_h = 5, .ofs_x = 1, .ofs_y = 5}, + {.bitmap_index = 1443, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1461, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1479, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1497, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1513, .adv_w = 192, .box_w = 11, .box_h = 17, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 1537, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1553, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1574, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1592, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1608, .adv_w = 192, .box_w = 9, .box_h = 19, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1630, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1648, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1666, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1684, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1700, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1716, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1732, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1750, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1768, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1786, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1804, .adv_w = 192, .box_w = 10, .box_h = 16, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 1824, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1842, .adv_w = 192, .box_w = 10, .box_h = 17, .ofs_x = 2, .ofs_y = -3}, + {.bitmap_index = 1864, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1880, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1898, .adv_w = 192, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 1920, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1941, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1959, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1977, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1993, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2011, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2029, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2043, .adv_w = 192, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2059, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2073, .adv_w = 192, .box_w = 8, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2084, .adv_w = 192, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 2104, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2117, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2134, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2148, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2161, .adv_w = 192, .box_w = 9, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2179, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2193, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2207, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2221, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2234, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2247, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2260, .adv_w = 192, .box_w = 9, .box_h = 15, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 2277, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2291, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2305, .adv_w = 192, .box_w = 10, .box_h = 15, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 2324, .adv_w = 192, .box_w = 10, .box_h = 18, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 2347, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2361, .adv_w = 192, .box_w = 10, .box_h = 14, .ofs_x = 2, .ofs_y = -3}, + {.bitmap_index = 2379, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2392, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2406, .adv_w = 192, .box_w = 11, .box_h = 13, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 2424, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2441, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2455, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2469, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2483, .adv_w = 192, .box_w = 10, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2497, .adv_w = 192, .box_w = 9, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2510, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2560, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2609, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2657, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2707, .adv_w = 240, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2736, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 2791, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2830, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2873, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 2901, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2949, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2988, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3027, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 3055, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3103, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3147, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3208, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3261, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3280, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3330, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3366, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3414, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3454, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3497, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3535, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3573, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3611, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3649, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3687, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3723, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3761, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3790, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 3828, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3894, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3943, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3993, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4053, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4106, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4167, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4222, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4275, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} }; /*--------------------- diff --git a/src/displayapp/fonts/open_sans_light.c b/src/displayapp/fonts/open_sans_light.c index 15f0ddf6da..84b7869049 100644 --- a/src/displayapp/fonts/open_sans_light.c +++ b/src/displayapp/fonts/open_sans_light.c @@ -1248,7 +1248,7 @@ lv_font_t open_sans_light = { #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, #endif -#if LV_VERSION_CHECK(7, 4, 0) +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 .underline_position = -11, .underline_thickness = 7, #endif From 13c66dd54b6ffcd3ea529457c3d5a0864ca1bdae Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sun, 27 Feb 2022 14:53:06 +0200 Subject: [PATCH 59/78] Further updates to font readme. --- src/displayapp/fonts/README.md | 33 +- .../jetbrains_mono_extrabold_compressed.c | 772 +++++++++--------- src/displayapp/fonts/lv_font_sys_48.c | 2 +- 3 files changed, 419 insertions(+), 388 deletions(-) diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index c8fb0d35b8..2e900d124e 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -29,9 +29,9 @@ static constexpr const char* newSymbol = "\xEF\x86\x85"; * Size: 20 * Bpp: 1 bit-per-pixel * Do not enable font compression or horizontal subpixel rendering -* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x20-0x7e, 0x410-0x44f` +* Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0x20-0x7e, 0x410-0x44f` * Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following - range : `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf072` + range: `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf072` * Fix an error in the font conversion. Replace the following: @@ -50,29 +50,44 @@ with (there are two changes: 7f -> 7e and f7 -> b7) - ### Medium font * Name: jetbrains_mono_42 * Size: 42 * Bpp: 1 bit-per-pixel * Do not enable font compression or horizontal subpixel rendering -* Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x25, 0x30-0x3a` +* Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0x25, 0x30-0x3a` ### Large font * Name: jetbrains_mono_76 * Size: 76 * Bpp: 1 bit-per-pixel * Do not enable font compression or horizontal subpixel rendering -* Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range : `0x25, 0x2D, 0x2F, 0x30-0x3a` +* Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0x25, 0x2D, 0x2F, 0x30-0x3a` + +### Digital watchface font + +* Name: jetbrains_mono_extrabold_compressed +* Size: 80 +* Bpp: 1 bit-per-pixel +* Do not enable font compression or horizontal subpixel rendering +* Load the file `JetBrainsMono-ExtraBold.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0x30-0x3a` ### PineTimeStyle font -* Name : open_sans_light -* Size : 150 -* Bpp : 1 bit-per-pixel +* Name: open_sans_light +* Size: 150 +* Bpp: 1 bit-per-pixel +* Do not enable font compression or horizontal subpixel rendering +* Load the file `open_sans_light.tff` (use the file in this repo to ensure the version matches) and specify the following symbols: `0123456789` + +### Symbols font (Used in QuickSettings for example) + +* Name: lv_font_sys_48 +* Size: 48 +* Bpp: 1 bit-per-pixel * Do not enable font compression or horizontal subpixel rendering -* Load the file `open_sans_light.tff` (use the file in this repo to ensure the version matches) and specify the following symbols : `0123456789` +* Load the file `icons_sys_48.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0xe902, 0xe904-0xe907, 0xe90b-0xe90c` #### Navigation font diff --git a/src/displayapp/fonts/jetbrains_mono_extrabold_compressed.c b/src/displayapp/fonts/jetbrains_mono_extrabold_compressed.c index c9917e40c1..ab0a5c4e8e 100644 --- a/src/displayapp/fonts/jetbrains_mono_extrabold_compressed.c +++ b/src/displayapp/fonts/jetbrains_mono_extrabold_compressed.c @@ -1,11 +1,15 @@ -#include "lvgl/lvgl.h" - /******************************************************************************* * Size: 80 px * Bpp: 1 * Opts: ******************************************************************************/ +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + #ifndef JETBRAINS_MONO_EXTRABOLD_COMPRESSED #define JETBRAINS_MONO_EXTRABOLD_COMPRESSED 1 #endif @@ -17,418 +21,412 @@ *----------------*/ /*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { - /* U+30 "0" */ - 0x0, 0x1, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, - 0xfe, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xc0, 0x0, - 0x3f, 0xff, 0xff, 0xf8, 0x0, 0x3f, 0xff, 0xff, - 0xfe, 0x0, 0x3f, 0xff, 0xff, 0xff, 0x80, 0x3f, - 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, - 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xff, 0xff, 0x1f, 0xff, 0xe0, 0x3f, 0xff, - 0xcf, 0xff, 0xc0, 0x7, 0xff, 0xe7, 0xff, 0xc0, - 0x1, 0xff, 0xf7, 0xff, 0xc0, 0x0, 0x7f, 0xff, - 0xff, 0xe0, 0x0, 0x3f, 0xff, 0xff, 0xe0, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x7, 0xff, 0xff, - 0xf8, 0x0, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x1, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0x80, 0x0, 0x3f, - 0xff, 0xff, 0xc0, 0x70, 0x1f, 0xff, 0xff, 0xe0, - 0x7c, 0xf, 0xff, 0xff, 0xf0, 0x7f, 0x7, 0xff, - 0xff, 0xf8, 0x3f, 0x83, 0xff, 0xff, 0xfc, 0x1f, - 0xc1, 0xff, 0xff, 0xfe, 0xf, 0xe0, 0xff, 0xff, - 0xff, 0x7, 0xf0, 0x7f, 0xff, 0xff, 0x83, 0xf8, - 0x3f, 0xff, 0xff, 0xc1, 0xfc, 0x1f, 0xff, 0xff, - 0xe0, 0xfe, 0xf, 0xff, 0xff, 0xf0, 0x7f, 0x7, - 0xff, 0xff, 0xf8, 0x3f, 0x83, 0xff, 0xff, 0xfc, - 0x1f, 0xc1, 0xff, 0xff, 0xfe, 0xf, 0xe0, 0xff, - 0xff, 0xff, 0x3, 0xe0, 0x7f, 0xff, 0xff, 0x80, - 0xe0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x1f, 0xff, - 0xff, 0xe0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x7, 0xff, 0xff, 0xf8, 0x0, 0x3, 0xff, 0xff, - 0xfc, 0x0, 0x1, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0xff, 0xff, 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, - 0xc0, 0x0, 0x7f, 0xf9, 0xff, 0xf0, 0x0, 0x7f, - 0xfc, 0xff, 0xfc, 0x0, 0x7f, 0xfe, 0x7f, 0xff, - 0x80, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0x7, 0xff, 0xff, 0xff, 0xff, 0x3, 0xff, 0xff, - 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0x80, - 0x3f, 0xff, 0xff, 0xff, 0x80, 0xf, 0xff, 0xff, - 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x7f, 0xf0, 0x0, 0x0, - - /* U+31 "1" */ - 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0xf, 0xff, - 0xe0, 0x0, 0x0, 0x3f, 0xff, 0xe0, 0x0, 0x0, - 0x7f, 0xff, 0xe0, 0x0, 0x1, 0xff, 0xff, 0xe0, - 0x0, 0x3, 0xff, 0xff, 0xe0, 0x0, 0x7, 0xff, - 0xff, 0xe0, 0x0, 0x1f, 0xff, 0xff, 0xe0, 0x0, - 0x3f, 0xff, 0xff, 0xe0, 0x0, 0x7f, 0xff, 0xff, - 0xe0, 0x0, 0x7f, 0xff, 0xff, 0xe0, 0x0, 0x7f, - 0xfd, 0xff, 0xe0, 0x0, 0x7f, 0xf9, 0xff, 0xe0, - 0x0, 0x7f, 0xf1, 0xff, 0xe0, 0x0, 0x7f, 0xe1, - 0xff, 0xe0, 0x0, 0x7f, 0x81, 0xff, 0xe0, 0x0, - 0x7f, 0x1, 0xff, 0xe0, 0x0, 0x7c, 0x1, 0xff, - 0xe0, 0x0, 0x78, 0x1, 0xff, 0xe0, 0x0, 0x60, - 0x1, 0xff, 0xe0, 0x0, 0x40, 0x1, 0xff, 0xe0, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, - 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, - 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, - 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, - 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, - 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, - 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, - 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, - 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, - 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0030 "0" */ + 0x0, 0x3, 0xff, 0x80, 0x0, 0x0, 0x3f, 0xff, + 0xe0, 0x0, 0x1, 0xff, 0xff, 0xf0, 0x0, 0xf, + 0xff, 0xff, 0xf8, 0x0, 0x3f, 0xff, 0xff, 0xf8, + 0x0, 0xff, 0xff, 0xff, 0xf8, 0x3, 0xff, 0xff, + 0xff, 0xf8, 0xf, 0xff, 0xff, 0xff, 0xf8, 0x3f, + 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, + 0xf1, 0xff, 0xfc, 0x7, 0xff, 0xf3, 0xff, 0xe0, + 0x3, 0xff, 0xe7, 0xff, 0x80, 0x3, 0xff, 0xdf, + 0xfe, 0x0, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x3, + 0xff, 0xff, 0xf0, 0x0, 0x7, 0xff, 0xff, 0xe0, + 0x0, 0xf, 0xff, 0xff, 0xc0, 0x0, 0x1f, 0xff, + 0xff, 0x80, 0x0, 0x3f, 0xff, 0xff, 0x0, 0x0, + 0x7f, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0xfc, + 0x0, 0x1, 0xff, 0xff, 0xf8, 0x0, 0x3, 0xff, + 0xff, 0xf0, 0x0, 0x7, 0xff, 0xff, 0xe0, 0x7c, + 0xf, 0xff, 0xff, 0xc1, 0xfe, 0x1f, 0xff, 0xff, + 0x87, 0xfc, 0x3f, 0xff, 0xff, 0x1f, 0xfc, 0x7f, + 0xff, 0xfe, 0x3f, 0xf8, 0xff, 0xff, 0xfc, 0x7f, + 0xf1, 0xff, 0xff, 0xf8, 0xff, 0xe3, 0xff, 0xff, + 0xf1, 0xff, 0xc7, 0xff, 0xff, 0xe1, 0xff, 0xf, + 0xff, 0xff, 0xc1, 0xfc, 0x1f, 0xff, 0xff, 0x81, + 0xf0, 0x3f, 0xff, 0xff, 0x0, 0x0, 0x7f, 0xff, + 0xfe, 0x0, 0x0, 0xff, 0xff, 0xfc, 0x0, 0x1, + 0xff, 0xff, 0xf8, 0x0, 0x3, 0xff, 0xff, 0xf0, + 0x0, 0x7, 0xff, 0xff, 0xe0, 0x0, 0xf, 0xff, + 0xff, 0xc0, 0x0, 0x1f, 0xff, 0xff, 0x80, 0x0, + 0x3f, 0xff, 0xff, 0x0, 0x0, 0x7f, 0xff, 0xfe, + 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x1, 0xff, + 0xff, 0xfc, 0x0, 0x7, 0xff, 0xbf, 0xfc, 0x0, + 0x1f, 0xfe, 0x7f, 0xfc, 0x0, 0x7f, 0xfc, 0xff, + 0xfe, 0x3, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xe1, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, + 0xff, 0xff, 0x1, 0xff, 0xff, 0xff, 0xfc, 0x1, + 0xff, 0xff, 0xff, 0xf0, 0x1, 0xff, 0xff, 0xff, + 0xc0, 0x1, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff, + 0xff, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0xc0, 0x0, + 0x0, 0x1f, 0xfc, 0x0, 0x0, + + /* U+0031 "1" */ + 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x3f, 0xff, + 0x80, 0x0, 0x1, 0xff, 0xfe, 0x0, 0x0, 0x1f, + 0xff, 0xf8, 0x0, 0x0, 0xff, 0xff, 0xe0, 0x0, + 0x7, 0xff, 0xff, 0x80, 0x0, 0x7f, 0xff, 0xfe, + 0x0, 0x3, 0xff, 0xff, 0xf8, 0x0, 0x3f, 0xff, + 0xff, 0xe0, 0x1, 0xff, 0xff, 0xff, 0x80, 0xf, + 0xff, 0xff, 0xfe, 0x0, 0x3f, 0xff, 0xff, 0xf8, + 0x0, 0xff, 0xfd, 0xff, 0xe0, 0x3, 0xff, 0xc7, + 0xff, 0x80, 0xf, 0xfe, 0x1f, 0xfe, 0x0, 0x3f, + 0xe0, 0x7f, 0xf8, 0x0, 0xff, 0x1, 0xff, 0xe0, + 0x3, 0xf8, 0x7, 0xff, 0x80, 0xf, 0x80, 0x1f, + 0xfe, 0x0, 0x3c, 0x0, 0x7f, 0xf8, 0x0, 0xe0, + 0x1, 0xff, 0xe0, 0x2, 0x0, 0x7, 0xff, 0x80, + 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x7f, + 0xf8, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, + 0x7, 0xff, 0x80, 0x0, 0x0, 0x1f, 0xfe, 0x0, + 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0x1, 0xff, + 0xe0, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, + 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, + 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, + 0x80, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, + 0x7f, 0xf8, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, + 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x1f, 0xfe, + 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0x1, + 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, + 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x7f, 0xf8, + 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x7, + 0xff, 0x80, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, + 0x0, 0x7f, 0xf8, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, + 0xc0, - /* U+32 "2" */ - 0x0, 0x1, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, - 0xfc, 0x0, 0x0, 0x1f, 0xff, 0xff, 0x80, 0x0, - 0x3f, 0xff, 0xff, 0xf0, 0x0, 0x3f, 0xff, 0xff, - 0xfc, 0x0, 0x3f, 0xff, 0xff, 0xff, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, - 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xe0, 0x7f, 0xff, - 0x8f, 0xff, 0xc0, 0xf, 0xff, 0xc7, 0xff, 0xc0, - 0x3, 0xff, 0xe7, 0xff, 0xc0, 0x0, 0xff, 0xfb, - 0xff, 0xc0, 0x0, 0x7f, 0xfd, 0xff, 0xe0, 0x0, - 0x1f, 0xfe, 0xff, 0xf0, 0x0, 0xf, 0xff, 0x0, - 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x3, - 0xff, 0xc0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, - 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xfe, - 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xff, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, 0x3f, - 0xff, 0x80, 0x0, 0x0, 0x7f, 0xff, 0x80, 0x0, - 0x0, 0x7f, 0xff, 0x80, 0x0, 0x0, 0x7f, 0xff, - 0x80, 0x0, 0x0, 0x7f, 0xff, 0x80, 0x0, 0x0, - 0xff, 0xff, 0x80, 0x0, 0x0, 0xff, 0xff, 0x80, - 0x0, 0x0, 0xff, 0xff, 0x80, 0x0, 0x0, 0xff, - 0xff, 0x80, 0x0, 0x1, 0xff, 0xff, 0x0, 0x0, - 0x1, 0xff, 0xff, 0x0, 0x0, 0x1, 0xff, 0xff, - 0x0, 0x0, 0x1, 0xff, 0xfe, 0x0, 0x0, 0x3, - 0xff, 0xfe, 0x0, 0x0, 0x3, 0xff, 0xfe, 0x0, - 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, 0x3, 0xff, - 0xfc, 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, - 0xdf, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, - 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xfb, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + /* U+0032 "2" */ + 0x0, 0x1, 0xff, 0x80, 0x0, 0x0, 0x3f, 0xff, + 0xe0, 0x0, 0x1, 0xff, 0xff, 0xf8, 0x0, 0xf, + 0xff, 0xff, 0xf8, 0x0, 0x3f, 0xff, 0xff, 0xf8, + 0x0, 0xff, 0xff, 0xff, 0xfc, 0x3, 0xff, 0xff, + 0xff, 0xf8, 0xf, 0xff, 0xff, 0xff, 0xf8, 0x1f, + 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xfc, + 0xf, 0xff, 0xe7, 0xff, 0xe0, 0xf, 0xff, 0xcf, + 0xff, 0x80, 0xf, 0xff, 0xff, 0xfe, 0x0, 0xf, + 0xff, 0xff, 0xfc, 0x0, 0x1f, 0xff, 0xff, 0xf0, + 0x0, 0x1f, 0xff, 0xff, 0xe0, 0x0, 0x3f, 0xff, + 0xff, 0xc0, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0x0, + 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, + 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, + 0x0, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, + 0x7f, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, + 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0xf, 0xff, + 0xc0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, + 0xff, 0xfc, 0x0, 0x0, 0x3, 0xff, 0xf8, 0x0, + 0x0, 0xf, 0xff, 0xe0, 0x0, 0x0, 0x3f, 0xff, + 0x80, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0x3, + 0xff, 0xfc, 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, + 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, 0xff, 0xff, + 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, 0xf, + 0xff, 0xf0, 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x3, 0xff, 0xf8, + 0x0, 0x0, 0xf, 0xff, 0xe0, 0x0, 0x0, 0x3f, + 0xff, 0x80, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, + 0x3, 0xff, 0xf8, 0x0, 0x0, 0xf, 0xff, 0xe0, + 0x0, 0x0, 0x3f, 0xff, 0x80, 0x0, 0x0, 0xff, + 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xfb, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xc0, + 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfb, + 0xff, 0xff, 0xff, 0xff, 0xf0, - /* U+33 "3" */ - 0x1f, 0xff, 0xff, 0xff, 0xfe, 0xf, 0xff, 0xff, - 0xff, 0xff, 0x7, 0xff, 0xff, 0xff, 0xff, 0x83, - 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, + /* U+0033 "3" */ + 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, + 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, + 0x83, 0xff, 0xff, 0xff, 0xff, 0x7, 0xff, 0xff, + 0xff, 0xfe, 0xf, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, - 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0xf, 0xff, - 0xff, 0x8f, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x80, 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, - 0x1f, 0xff, 0x80, 0x0, 0x0, 0x3f, 0xff, 0x80, - 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, 0x3f, - 0xff, 0x0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xfe, - 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, - 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, 0xf, - 0xff, 0xf8, 0x0, 0x0, 0x7, 0xff, 0xff, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xe0, 0x0, 0x1, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0x80, 0x0, 0x3f, 0xff, - 0xff, 0xe0, 0x0, 0x1f, 0xff, 0xff, 0xf0, 0x0, - 0xf, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, - 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x1, 0xff, - 0xe0, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x1f, 0xfe, - 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, - 0x7, 0xff, 0x80, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0xff, 0xff, 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, - 0xc0, 0x0, 0x7f, 0xf9, 0xff, 0xf0, 0x0, 0x7f, - 0xfc, 0xff, 0xfc, 0x0, 0x7f, 0xfe, 0x7f, 0xff, - 0x80, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0xf, 0xff, 0xff, 0xff, 0xff, 0x3, 0xff, 0xff, - 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0x80, - 0x3f, 0xff, 0xff, 0xff, 0x80, 0xf, 0xff, 0xff, - 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x7f, 0xf0, 0x0, 0x0, + 0xf0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, + 0xf, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, + 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, + 0xc0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, + 0x7f, 0xf8, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, + 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x1f, 0xfe, + 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0x1, + 0xff, 0xf8, 0x0, 0x0, 0x3, 0xff, 0xfe, 0x0, + 0x0, 0x7, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, + 0xff, 0x80, 0x0, 0x1f, 0xff, 0xff, 0x80, 0x0, + 0x3f, 0xff, 0xff, 0x80, 0x0, 0x7f, 0xff, 0xff, + 0x80, 0x0, 0xff, 0xff, 0xff, 0x80, 0x1, 0xff, + 0xff, 0xff, 0x0, 0x3, 0xff, 0xff, 0xff, 0x0, + 0x0, 0x0, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x7f, + 0xfc, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, + 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x3, + 0xff, 0xc0, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, + 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x1f, 0xfe, + 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, + 0x7f, 0xff, 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, + 0x0, 0x1, 0xff, 0xff, 0xff, 0x0, 0x7, 0xff, + 0xff, 0xfe, 0x0, 0xf, 0xff, 0xbf, 0xfe, 0x0, + 0x3f, 0xfe, 0x7f, 0xff, 0x1, 0xff, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, + 0xff, 0xff, 0x1, 0xff, 0xff, 0xff, 0xfc, 0x1, + 0xff, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, + 0x80, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x7f, + 0xff, 0xf0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, - /* U+34 "4" */ + /* U+0034 "4" */ 0x0, 0x0, 0x3, 0xff, 0xf0, 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x80, - 0x0, 0x0, 0xff, 0xfc, 0x0, 0x0, 0x3, 0xff, - 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, - 0xff, 0xfc, 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, + 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x3, 0xff, + 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, + 0xff, 0xfc, 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, 0xff, 0xfc, - 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0x3f, - 0xff, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, - 0x7, 0xff, 0xe0, 0x0, 0x0, 0x3f, 0xff, 0x0, + 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x1f, + 0xff, 0x0, 0x0, 0x0, 0xff, 0xfc, 0x0, 0x0, + 0x7, 0xff, 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x7, 0xff, - 0xc0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x1, - 0xff, 0xf8, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, - 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x1, 0xff, 0xf8, - 0x0, 0x0, 0xf, 0xff, 0xc0, 0x0, 0x0, 0x3f, - 0xfe, 0x0, 0xff, 0xf1, 0xff, 0xf0, 0x3, 0xff, - 0xcf, 0xff, 0xc0, 0xf, 0xff, 0x7f, 0xfe, 0x0, - 0x3f, 0xfd, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, + 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, + 0xff, 0xf8, 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, + 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, 0xff, 0xf8, + 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x3f, + 0xff, 0x0, 0xff, 0xf0, 0xff, 0xf8, 0x3, 0xff, + 0xc7, 0xff, 0xc0, 0xf, 0xff, 0x3f, 0xff, 0x0, + 0x3f, 0xfd, 0xff, 0xf8, 0x0, 0xff, 0xf7, 0xff, 0xc0, 0x3, 0xff, 0xff, 0xfe, 0x0, 0xf, 0xff, - 0xff, 0xf0, 0x0, 0x3f, 0xff, 0xff, 0x80, 0x0, + 0xff, 0xf8, 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x3, 0xff, 0xff, 0xf8, 0x0, 0xf, 0xff, 0xff, 0xe0, 0x0, 0x3f, 0xff, + 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, - 0x0, 0x0, 0xff, 0xf0, + 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, + 0xc0, - /* U+35 "5" */ - 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, 0x87, - 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, - 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, - 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, - 0xff, 0xff, 0xff, 0xf, 0xff, 0x0, 0x0, 0x0, - 0x7, 0xff, 0x80, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, - 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x1f, - 0xfe, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, - 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x3, 0xff, - 0xc0, 0x7f, 0x80, 0x1, 0xff, 0xe1, 0xff, 0xf8, - 0x0, 0xff, 0xf1, 0xff, 0xff, 0x0, 0x7f, 0xf9, - 0xff, 0xff, 0xc0, 0x3f, 0xfd, 0xff, 0xff, 0xf0, - 0x1f, 0xff, 0xff, 0xff, 0xfc, 0xf, 0xff, 0xff, - 0xff, 0xff, 0x7, 0xff, 0xff, 0xff, 0xff, 0xc3, - 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xfc, 0x7, - 0xff, 0xf8, 0xff, 0xf8, 0x0, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0xf, - 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, - 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, - 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x1f, 0xfe, - 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, - 0x7, 0xff, 0x80, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0x0, 0x1, - 0xff, 0xff, 0xff, 0x80, 0x0, 0xff, 0xfb, 0xff, - 0xe0, 0x0, 0xff, 0xf9, 0xff, 0xf8, 0x0, 0xff, - 0xfc, 0xff, 0xff, 0x81, 0xff, 0xfe, 0x3f, 0xff, - 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0x7, 0xff, 0xff, 0xff, 0xff, 0x1, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x7f, 0xff, 0xff, 0xff, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0x0, 0x7, 0xff, 0xff, - 0xff, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x1f, 0xff, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xe0, - 0x0, 0x0, + /* U+0035 "5" */ + 0x7f, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, + 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xf1, + 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, + 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xc7, + 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0x0, 0x0, + 0x0, 0x7f, 0xf8, 0x0, 0x0, 0x1, 0xff, 0xe0, + 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x1f, + 0xfe, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, + 0x1, 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, 0x80, + 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x7f, + 0xf8, 0x1f, 0xf0, 0x1, 0xff, 0xe1, 0xff, 0xf0, + 0x7, 0xff, 0x9f, 0xff, 0xf0, 0x1f, 0xfe, 0xff, + 0xff, 0xe0, 0x7f, 0xfb, 0xff, 0xff, 0xc1, 0xff, + 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, + 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, + 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, + 0xf0, 0x3f, 0xff, 0x9f, 0xff, 0x0, 0x3f, 0xfe, + 0x7f, 0xf8, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x1, + 0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, + 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x3f, 0xfc, + 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x3, + 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, + 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0xf, + 0xff, 0xff, 0xf0, 0x0, 0x3f, 0xff, 0xff, 0xc0, + 0x0, 0xff, 0xff, 0xff, 0x0, 0x7, 0xff, 0xff, + 0xfe, 0x0, 0x1f, 0xfe, 0xff, 0xfc, 0x0, 0xff, + 0xf9, 0xff, 0xfc, 0xf, 0xff, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, 0xfc, 0x3f, + 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, + 0x80, 0xff, 0xff, 0xff, 0xfc, 0x1, 0xff, 0xff, + 0xff, 0xe0, 0x3, 0xff, 0xff, 0xfe, 0x0, 0x3, + 0xff, 0xff, 0xf0, 0x0, 0x3, 0xff, 0xff, 0x0, + 0x0, 0x1, 0xff, 0xc0, 0x0, - /* U+36 "6" */ - 0x0, 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0x7, - 0xff, 0xe0, 0x0, 0x0, 0x3, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7f, - 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, - 0xc0, 0x0, 0x0, 0x3, 0xff, 0xf0, 0x0, 0x0, + /* U+0036 "6" */ + 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x1f, + 0xff, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, + 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, + 0x80, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, + 0x7, 0xff, 0xc0, 0x0, 0x0, 0x7, 0xff, 0xc0, + 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x3, + 0xff, 0xe0, 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, + 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, + 0xf0, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfc, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, - 0xf, 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, 0xc0, - 0x0, 0x0, 0x3, 0xff, 0xf0, 0x0, 0x0, 0x1, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, - 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0xf, - 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, - 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x3f, 0xc0, - 0x0, 0x1f, 0xfe, 0x3f, 0xfe, 0x0, 0xf, 0xff, - 0xbf, 0xff, 0xe0, 0x3, 0xff, 0xdf, 0xff, 0xfc, - 0x1, 0xff, 0xef, 0xff, 0xff, 0x80, 0x7f, 0xff, - 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xfe, - 0xf, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, - 0xff, 0xff, 0xf1, 0xff, 0xff, 0x3, 0xff, 0xfc, - 0x7f, 0xff, 0x0, 0x3f, 0xff, 0x9f, 0xff, 0x0, - 0x3, 0xff, 0xef, 0xff, 0xc0, 0x0, 0xff, 0xfb, - 0xff, 0xe0, 0x0, 0x1f, 0xff, 0xff, 0xf8, 0x0, - 0x7, 0xff, 0xff, 0xfc, 0x0, 0x0, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x3, 0xff, 0xff, - 0xfc, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xe0, 0x0, 0x1f, 0xff, 0x7f, - 0xf8, 0x0, 0x7, 0xff, 0xdf, 0xfe, 0x0, 0x3, - 0xff, 0xe7, 0xff, 0xc0, 0x0, 0xff, 0xf9, 0xff, - 0xfc, 0x0, 0xff, 0xfe, 0x3f, 0xff, 0xc0, 0xff, - 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, - 0xf0, 0x7, 0xff, 0xff, 0xff, 0xf8, 0x0, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x1f, 0xff, 0xff, 0xfe, - 0x0, 0x3, 0xff, 0xff, 0xff, 0x0, 0x0, 0x3f, - 0xff, 0xff, 0x0, 0x0, 0x3, 0xff, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xfc, 0x0, 0x0, - - /* U+37 "7" */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x0, + 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, + 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x1f, + 0xff, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, + 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, + 0x87, 0xf8, 0x0, 0x7, 0xff, 0x8f, 0xff, 0x0, + 0x7, 0xff, 0xcf, 0xff, 0xe0, 0x3, 0xff, 0xdf, + 0xff, 0xf8, 0x3, 0xff, 0xef, 0xff, 0xfe, 0x1, + 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, + 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x81, 0xff, + 0xff, 0x3f, 0xff, 0x0, 0x3f, 0xff, 0x9f, 0xff, + 0x0, 0x7, 0xff, 0xdf, 0xff, 0x80, 0x3, 0xff, + 0xef, 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, 0xc0, + 0x0, 0x7f, 0xff, 0xff, 0xc0, 0x0, 0x1f, 0xff, + 0xff, 0xe0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, + 0x7, 0xff, 0xff, 0xf8, 0x0, 0x3, 0xff, 0xff, + 0xfc, 0x0, 0x1, 0xff, 0xff, 0xfe, 0x0, 0x0, + 0xff, 0xff, 0xff, 0x80, 0x0, 0xff, 0xfb, 0xff, + 0xc0, 0x0, 0x7f, 0xfd, 0xff, 0xf0, 0x0, 0x7f, + 0xfc, 0xff, 0xf8, 0x0, 0x3f, 0xfe, 0x3f, 0xfe, + 0x0, 0x3f, 0xff, 0x1f, 0xff, 0xc0, 0x7f, 0xff, + 0x7, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, + 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x3f, 0xff, 0xff, 0xff, 0xc0, 0xf, 0xff, 0xff, + 0xff, 0xc0, 0x3, 0xff, 0xff, 0xff, 0x80, 0x0, + 0xff, 0xff, 0xff, 0x80, 0x0, 0x1f, 0xff, 0xff, + 0x0, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x0, 0x0, + 0x3f, 0xf8, 0x0, 0x0, + + /* U+0037 "7" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x0, 0xf, 0xff, 0xff, 0xe0, 0x0, 0x1f, - 0xfe, 0xff, 0xe0, 0x0, 0x1f, 0xfe, 0xff, 0xe0, - 0x0, 0x3f, 0xfc, 0xff, 0xe0, 0x0, 0x3f, 0xfc, - 0xff, 0xe0, 0x0, 0x7f, 0xf8, 0xff, 0xe0, 0x0, - 0x7f, 0xf8, 0xff, 0xe0, 0x0, 0xff, 0xf8, 0xff, - 0xe0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, - 0xf0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, - 0x3, 0xff, 0xe0, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x7, - 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, - 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x3, 0xff, + 0xff, 0xfe, 0x0, 0x1, 0xff, 0xef, 0xff, 0x0, + 0x1, 0xff, 0xf7, 0xff, 0x80, 0x0, 0xff, 0xf3, + 0xff, 0xc0, 0x0, 0xff, 0xf9, 0xff, 0xe0, 0x0, + 0x7f, 0xfc, 0xff, 0xf0, 0x0, 0x7f, 0xfc, 0x7f, + 0xf8, 0x0, 0x3f, 0xfe, 0x3f, 0xfc, 0x0, 0x3f, + 0xfe, 0x1f, 0xfe, 0x0, 0x1f, 0xff, 0x0, 0x0, + 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, + 0x80, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, + 0x7, 0xff, 0xc0, 0x0, 0x0, 0x3, 0xff, 0xe0, + 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x1, + 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, + 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, + 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, + 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, - 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, - 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x7f, - 0xfc, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, - 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, 0xf8, - 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, 0x1, - 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, + 0x1f, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x80, + 0x0, 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0x7, + 0xff, 0xc0, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x3, 0xff, - 0xc0, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, - 0x7, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, 0x80, - 0x0, 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0x1f, - 0xff, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, - 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xfe, + 0xe0, 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, + 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x0, - 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, - 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, - 0xf8, 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, - 0x1, 0xff, 0xf0, 0x0, 0x0, 0x3, 0xff, 0xe0, + 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, + 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x1f, + 0xff, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, + 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, + 0xc0, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, + 0x3, 0xff, 0xe0, 0x0, 0x0, 0x3, 0xff, 0xe0, + 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, 0x1, + 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, - /* U+38 "8" */ - 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0x80, 0x0, 0x7, 0xff, 0xff, 0xf8, 0x0, - 0x7, 0xff, 0xff, 0xff, 0x80, 0x3, 0xff, 0xff, - 0xff, 0xf0, 0x1, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, - 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0xf, - 0xff, 0xe0, 0x3f, 0xff, 0xc3, 0xff, 0xe0, 0x3, - 0xff, 0xf0, 0xff, 0xf0, 0x0, 0x7f, 0xfc, 0x7f, - 0xf8, 0x0, 0xf, 0xff, 0x9f, 0xfe, 0x0, 0x3, - 0xff, 0xe7, 0xff, 0x0, 0x0, 0x7f, 0xf9, 0xff, - 0xc0, 0x0, 0x1f, 0xfe, 0x7f, 0xf0, 0x0, 0x7, - 0xff, 0x9f, 0xfc, 0x0, 0x1, 0xff, 0xe7, 0xff, - 0x0, 0x0, 0x7f, 0xf9, 0xff, 0xc0, 0x0, 0x1f, - 0xfe, 0x3f, 0xf8, 0x0, 0xf, 0xff, 0xf, 0xfe, - 0x0, 0x3, 0xff, 0xc3, 0xff, 0xc0, 0x1, 0xff, - 0xe0, 0x7f, 0xf8, 0x0, 0xff, 0xf8, 0xf, 0xff, - 0x80, 0xff, 0xfc, 0x1, 0xff, 0xff, 0xff, 0xfe, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0x0, 0x7, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x7f, 0xff, 0xff, 0x0, - 0x0, 0x3, 0xff, 0xfe, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xf0, 0x0, 0x7, 0xff, 0xff, 0xff, 0x80, - 0x7, 0xff, 0xff, 0xff, 0xf0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0x1, 0xff, 0xf8, 0xf, 0xff, 0xe0, - 0xff, 0xf8, 0x0, 0x7f, 0xf8, 0x3f, 0xfc, 0x0, - 0xf, 0xff, 0x1f, 0xfe, 0x0, 0x1, 0xff, 0xe7, - 0xff, 0x80, 0x0, 0x7f, 0xfb, 0xff, 0xc0, 0x0, - 0xf, 0xfe, 0xff, 0xf0, 0x0, 0x3, 0xff, 0xff, - 0xfc, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xc0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x3, 0xff, 0xff, 0xfe, 0x0, 0x1, - 0xff, 0xff, 0xff, 0x80, 0x0, 0x7f, 0xff, 0xff, - 0xf0, 0x0, 0x3f, 0xff, 0x7f, 0xfe, 0x0, 0x1f, - 0xff, 0x9f, 0xff, 0xe0, 0x3f, 0xff, 0xe3, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x3, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0x80, 0xf, 0xff, 0xff, 0xff, 0xc0, 0x1, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x1f, 0xff, 0xff, 0xe0, - 0x0, 0x1, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x7, - 0xff, 0x80, 0x0, - - /* U+39 "9" */ - 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0x0, 0x0, 0x3, 0xff, 0xff, 0xf0, 0x0, - 0x3, 0xff, 0xff, 0xff, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xe0, 0x1, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, - 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0xf, - 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xfc, 0xf, - 0xff, 0xf1, 0xff, 0xf8, 0x0, 0xff, 0xfc, 0x7f, - 0xfc, 0x0, 0xf, 0xff, 0x9f, 0xff, 0x0, 0x3, - 0xff, 0xef, 0xff, 0x80, 0x0, 0x7f, 0xfb, 0xff, - 0xe0, 0x0, 0x1f, 0xff, 0xff, 0xf0, 0x0, 0x3, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x3, 0xff, 0xff, 0xfc, - 0x0, 0x0, 0xff, 0xff, 0xff, 0x80, 0x0, 0x7f, - 0xff, 0xff, 0xe0, 0x0, 0x1f, 0xff, 0x7f, 0xf8, - 0x0, 0xf, 0xff, 0xdf, 0xff, 0x0, 0x3, 0xff, - 0xe7, 0xff, 0xf0, 0x3, 0xff, 0xf8, 0xff, 0xff, - 0x3, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0x87, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xf8, - 0x7, 0xff, 0xff, 0xdf, 0xfe, 0x0, 0xff, 0xff, - 0xef, 0xff, 0x80, 0x1f, 0xff, 0xf7, 0xff, 0xc0, - 0x1, 0xff, 0xf1, 0xff, 0xf0, 0x0, 0xf, 0xf0, + /* U+0038 "8" */ + 0x0, 0x1, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, + 0xfc, 0x0, 0x0, 0x1f, 0xff, 0xff, 0x80, 0x0, + 0x1f, 0xff, 0xff, 0xf0, 0x0, 0x3f, 0xff, 0xff, + 0xfc, 0x0, 0x3f, 0xff, 0xff, 0xff, 0x0, 0x3f, + 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, + 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, + 0xff, 0xff, 0xfe, 0xf, 0xff, 0xe0, 0x7f, 0xff, + 0x7, 0xff, 0xc0, 0xf, 0xff, 0x87, 0xff, 0xc0, + 0x3, 0xff, 0xe3, 0xff, 0xe0, 0x1, 0xff, 0xf1, + 0xff, 0xe0, 0x0, 0x7f, 0xf8, 0xff, 0xf0, 0x0, + 0x3f, 0xfc, 0x7f, 0xf8, 0x0, 0x1f, 0xfe, 0x3f, + 0xfc, 0x0, 0xf, 0xff, 0x1f, 0xfe, 0x0, 0x7, + 0xff, 0x8f, 0xff, 0x80, 0x7, 0xff, 0xc3, 0xff, + 0xc0, 0x3, 0xff, 0xc1, 0xff, 0xf0, 0x3, 0xff, + 0xe0, 0x7f, 0xfc, 0x3, 0xff, 0xe0, 0x3f, 0xff, + 0x3, 0xff, 0xf0, 0xf, 0xff, 0xe7, 0xff, 0xf0, + 0x3, 0xff, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, + 0xff, 0xf0, 0x0, 0x1f, 0xff, 0xff, 0xf0, 0x0, + 0x7, 0xff, 0xff, 0xf0, 0x0, 0x1, 0xff, 0xff, + 0xf0, 0x0, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x3, + 0xff, 0xff, 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, + 0xe0, 0x3, 0xff, 0xff, 0xff, 0xf8, 0x3, 0xff, + 0xf0, 0xff, 0xfe, 0x3, 0xff, 0xf0, 0x1f, 0xff, + 0x83, 0xff, 0xe0, 0x7, 0xff, 0xe3, 0xff, 0xe0, + 0x1, 0xff, 0xf1, 0xff, 0xe0, 0x0, 0x7f, 0xfc, + 0xff, 0xf0, 0x0, 0x1f, 0xfe, 0xff, 0xf0, 0x0, + 0x7, 0xff, 0xff, 0xf8, 0x0, 0x3, 0xff, 0xff, + 0xfc, 0x0, 0x1, 0xff, 0xff, 0xfe, 0x0, 0x0, + 0xff, 0xff, 0xff, 0x0, 0x0, 0x7f, 0xff, 0xff, + 0xc0, 0x0, 0x7f, 0xff, 0xff, 0xe0, 0x0, 0x3f, + 0xff, 0xff, 0xf8, 0x0, 0x3f, 0xff, 0x7f, 0xfe, + 0x0, 0x3f, 0xff, 0x3f, 0xff, 0xc0, 0x7f, 0xff, + 0x9f, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, + 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, + 0xff, 0xe0, 0x7, 0xff, 0xff, 0xff, 0xe0, 0x1, + 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3f, 0xff, 0xff, + 0x80, 0x0, 0x7, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x3f, 0xf8, 0x0, 0x0, + + /* U+0039 "9" */ + 0x0, 0x1, 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, + 0xfc, 0x0, 0x0, 0xf, 0xff, 0xff, 0x80, 0x0, + 0x1f, 0xff, 0xff, 0xf0, 0x0, 0x1f, 0xff, 0xff, + 0xfc, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x0, 0x1f, + 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, + 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, + 0xff, 0xff, 0xfe, 0xf, 0xff, 0xf0, 0x7f, 0xff, + 0x8f, 0xff, 0xe0, 0xf, 0xff, 0xc7, 0xff, 0xc0, + 0x1, 0xff, 0xf3, 0xff, 0xe0, 0x0, 0xff, 0xfb, + 0xff, 0xe0, 0x0, 0x3f, 0xfd, 0xff, 0xf0, 0x0, + 0x1f, 0xff, 0xff, 0xf0, 0x0, 0x7, 0xff, 0xff, + 0xf8, 0x0, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x1, + 0xff, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0xff, + 0x0, 0x0, 0x7f, 0xff, 0xff, 0x80, 0x0, 0x3f, + 0xff, 0xff, 0xe0, 0x0, 0x3f, 0xff, 0xff, 0xf0, + 0x0, 0x1f, 0xff, 0x7f, 0xfc, 0x0, 0x1f, 0xff, + 0x3f, 0xfe, 0x0, 0xf, 0xff, 0x9f, 0xff, 0xc0, + 0x1f, 0xff, 0xc7, 0xff, 0xf8, 0x3f, 0xff, 0xe3, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x1f, + 0xff, 0xff, 0xff, 0xf8, 0x7, 0xff, 0xff, 0xbf, + 0xfc, 0x1, 0xff, 0xff, 0xbf, 0xfc, 0x0, 0x7f, + 0xff, 0xbf, 0xfe, 0x0, 0xf, 0xff, 0x1f, 0xfe, + 0x0, 0x1, 0xfe, 0x1f, 0xff, 0x0, 0x0, 0x0, + 0xf, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x80, + 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x7, + 0xff, 0xc0, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, + 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x3, 0xff, + 0xe0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, + 0x1, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, 0xf, - 0xff, 0x80, 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, - 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x80, 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, - 0x1, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xf8, - 0x0, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x80, - 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0x3, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x0, 0x0, 0x3f, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x80, 0x0, - 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x3f, + 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, + 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x1f, 0xff, + 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, + 0xf, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, 0x80, + 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x7, + 0xff, 0xc0, 0x0, 0x0, - /* U+3A ":" */ + /* U+003A ":" */ 0x7, 0xe0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, - 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, - 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, 0x7, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, + 0x1f, 0xf8, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xe0, 0x1f, 0xf8, - 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x7, 0xe0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, 0x7, 0xe0 }; @@ -439,17 +437,17 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 768, .box_w = 41, .box_h = 59, .ofs_x = 4, .ofs_y = -1}, - {.bitmap_index = 303, .adv_w = 768, .box_w = 40, .box_h = 58, .ofs_x = 6, .ofs_y = 0}, - {.bitmap_index = 593, .adv_w = 768, .box_w = 41, .box_h = 58, .ofs_x = 4, .ofs_y = 0}, - {.bitmap_index = 891, .adv_w = 768, .box_w = 41, .box_h = 59, .ofs_x = 3, .ofs_y = -1}, - {.bitmap_index = 1194, .adv_w = 768, .box_w = 38, .box_h = 58, .ofs_x = 4, .ofs_y = 0}, - {.bitmap_index = 1470, .adv_w = 768, .box_w = 41, .box_h = 58, .ofs_x = 4, .ofs_y = -1}, - {.bitmap_index = 1768, .adv_w = 768, .box_w = 42, .box_h = 59, .ofs_x = 3, .ofs_y = -1}, - {.bitmap_index = 2078, .adv_w = 768, .box_w = 40, .box_h = 58, .ofs_x = 4, .ofs_y = 0}, - {.bitmap_index = 2368, .adv_w = 768, .box_w = 42, .box_h = 60, .ofs_x = 3, .ofs_y = -1}, - {.bitmap_index = 2683, .adv_w = 768, .box_w = 42, .box_h = 59, .ofs_x = 3, .ofs_y = 0}, - {.bitmap_index = 2993, .adv_w = 768, .box_w = 16, .box_h = 46, .ofs_x = 16, .ofs_y = -1} + {.bitmap_index = 0, .adv_w = 768, .box_w = 39, .box_h = 60, .ofs_x = 5, .ofs_y = -1}, + {.bitmap_index = 293, .adv_w = 768, .box_w = 38, .box_h = 59, .ofs_x = 6, .ofs_y = 0}, + {.bitmap_index = 574, .adv_w = 768, .box_w = 39, .box_h = 60, .ofs_x = 4, .ofs_y = 0}, + {.bitmap_index = 867, .adv_w = 768, .box_w = 39, .box_h = 59, .ofs_x = 4, .ofs_y = -1}, + {.bitmap_index = 1155, .adv_w = 768, .box_w = 38, .box_h = 59, .ofs_x = 4, .ofs_y = 0}, + {.bitmap_index = 1436, .adv_w = 768, .box_w = 38, .box_h = 60, .ofs_x = 5, .ofs_y = -1}, + {.bitmap_index = 1721, .adv_w = 768, .box_w = 41, .box_h = 60, .ofs_x = 4, .ofs_y = -1}, + {.bitmap_index = 2029, .adv_w = 768, .box_w = 41, .box_h = 58, .ofs_x = 4, .ofs_y = 0}, + {.bitmap_index = 2327, .adv_w = 768, .box_w = 41, .box_h = 60, .ofs_x = 4, .ofs_y = -1}, + {.bitmap_index = 2635, .adv_w = 768, .box_w = 41, .box_h = 60, .ofs_x = 4, .ofs_y = -1}, + {.bitmap_index = 2943, .adv_w = 768, .box_w = 16, .box_h = 46, .ofs_x = 16, .ofs_y = -1} }; /*--------------------- @@ -473,9 +471,14 @@ static const lv_font_fmt_txt_cmap_t cmaps[] = * ALL CUSTOM DATA *--------------------*/ +#if LV_VERSION_CHECK(8, 0, 0) /*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else static lv_font_fmt_txt_dsc_t font_dsc = { - .glyph_bitmap = gylph_bitmap, +#endif + .glyph_bitmap = glyph_bitmap, .glyph_dsc = glyph_dsc, .cmaps = cmaps, .kern_dsc = NULL, @@ -483,7 +486,10 @@ static lv_font_fmt_txt_dsc_t font_dsc = { .cmap_num = 1, .bpp = 1, .kern_classes = 0, - .bitmap_format = 0 + .bitmap_format = 0, +#if LV_VERSION_CHECK(8, 0, 0) + .cache = &cache +#endif }; @@ -492,16 +498,26 @@ static lv_font_fmt_txt_dsc_t font_dsc = { *----------------*/ /*Initialize a public general font descriptor*/ +#if LV_VERSION_CHECK(8, 0, 0) +const lv_font_t jetbrains_mono_extrabold_compressed = { +#else lv_font_t jetbrains_mono_extrabold_compressed = { +#endif .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 60, /*The maximum line height required by the font*/ + .line_height = 61, /*The maximum line height required by the font*/ .base_line = 1, /*Baseline measured from the bottom of the line*/ #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -12, + .underline_thickness = 4, #endif .dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ }; + + #endif /*#if JETBRAINS_MONO_EXTRABOLD_COMPRESSED*/ diff --git a/src/displayapp/fonts/lv_font_sys_48.c b/src/displayapp/fonts/lv_font_sys_48.c index 19f3ec2de1..ca007e30fe 100644 --- a/src/displayapp/fonts/lv_font_sys_48.c +++ b/src/displayapp/fonts/lv_font_sys_48.c @@ -311,7 +311,7 @@ lv_font_t lv_font_sys_48 = { #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, #endif -#if LV_VERSION_CHECK(7, 4, 0) +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 .underline_position = 0, .underline_thickness = 0, #endif From 04d21dcd932c7e75b2d45314b2f68d9ba91c5d68 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sun, 27 Feb 2022 15:02:02 +0200 Subject: [PATCH 60/78] Add ExtraBold font ttf --- .../fonts/JetBrainsMono-ExtraBold.ttf | Bin 0 -> 210688 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/displayapp/fonts/JetBrainsMono-ExtraBold.ttf diff --git a/src/displayapp/fonts/JetBrainsMono-ExtraBold.ttf b/src/displayapp/fonts/JetBrainsMono-ExtraBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f85a85b5f7dd416327ad0c5d9052ca94c5b764d7 GIT binary patch literal 210688 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

#uzTv)<~HSR4F^}`*|)bh57-+V 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 Cxm|q# literal 0 HcmV?d00001 From 61a9a97e267799f76c64279887a9845d4760a77c Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Tue, 1 Mar 2022 01:09:48 +0200 Subject: [PATCH 61/78] Update navigation font readme section --- src/displayapp/fonts/README.md | 16 ++++++---------- src/displayapp/fonts/lv_font_navi_80.c | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index 2e900d124e..7e6203ffb4 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -59,6 +59,7 @@ with * Load the file `JetBrainsMono-Regular.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0x25, 0x30-0x3a` ### Large font + * Name: jetbrains_mono_76 * Size: 76 * Bpp: 1 bit-per-pixel @@ -87,17 +88,12 @@ with * Size: 48 * Bpp: 1 bit-per-pixel * Do not enable font compression or horizontal subpixel rendering -* Load the file `icons_sys_48.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0xe902, 0xe904-0xe907, 0xe90b-0xe90c` - -#### Navigation font +* Load the file `icons_sys_48.tff` and specify the following range: `0xe902, 0xe904-0xe907, 0xe90b-0xe90c` -To create the navigtion.ttf I use the web app [icomoon](https://icomoon.io/app) -this app can import the svg files from the folder *src/displayapp/icons/navigation/unique* and create a ttf file the -project for the site is *lv_font_navi_80.json* you can import it to add or remove icons +### Navigation font -You can also use the online LVGL tool to create the .c +`navigtion.ttf` is created with the web app [icomoon](https://icomoon.io/app) by importing the svg files from `src/displayapp/icons/navigation/unique` and generating the font. `lv_font_navi_80.json` is a project file for the site, which you can import to add or remove icons. -ttf file : navigation.ttf name : lv_font_navi_80 size : 80px Bpp : 2 bit-per-pixel range : 0xe900-0xe929 +This font must be generated with the `lv_font_conv` tool, which has additional options not available in the online converter. -$lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 --no-prefilter -o -lv_font_navi_80.c +`lv_font_conv --font navigation.ttf -r '0xe900-0xe929' --size 80 --format lvgl --bpp 2 -o lv_font_navi_80.c` diff --git a/src/displayapp/fonts/lv_font_navi_80.c b/src/displayapp/fonts/lv_font_navi_80.c index d5a8400ebf..8fd3979f25 100644 --- a/src/displayapp/fonts/lv_font_navi_80.c +++ b/src/displayapp/fonts/lv_font_navi_80.c @@ -2623,7 +2623,7 @@ lv_font_t lv_font_navi_80 = { #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) .subpx = LV_FONT_SUBPX_NONE, #endif -#if LV_VERSION_CHECK(7, 4, 0) +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 .underline_position = 0, .underline_thickness = 0, #endif From 7e0b053b38d0491eb4ee666be34d0ea2ab029d19 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Tue, 8 Mar 2022 21:28:57 +0100 Subject: [PATCH 62/78] CI: lv_sim: initialize libpng submodule for WITH_PNG=ON screenshot InfiniSim PR https://github.com/InfiniTimeOrg/InfiniSim/pull/10 adds support for screenshots in png/bmp format using `libpng` submodule. This new submodule must be added to the lv_sim workflow as well. --- .github/workflows/lv_sim.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lv_sim.yml b/.github/workflows/lv_sim.yml index a3479f0501..59ee7b31e8 100644 --- a/.github/workflows/lv_sim.yml +++ b/.github/workflows/lv_sim.yml @@ -48,7 +48,7 @@ jobs: - name: Get InfiniSim repo run: | git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main - git -C InfiniSim submodule update --init lv_drivers + git -C InfiniSim submodule update --init lv_drivers libpng ######################################################################################### # CMake From f47b04ffd0ee401381f18cfedd716d492b4c7db8 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Tue, 8 Mar 2022 23:10:06 +0100 Subject: [PATCH 63/78] Fix SettingChimes cbOption array size There are 3 options, but the array-size is set to 2. This leads to memory corruption in the initialization of the SettingChimes screen when assigning the third option object pointer. Found in https://github.com/InfiniTimeOrg/InfiniSim/issues/11 --- src/displayapp/screens/settings/SettingChimes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/SettingChimes.h b/src/displayapp/screens/settings/SettingChimes.h index 653f87f7e5..a251e95b57 100644 --- a/src/displayapp/screens/settings/SettingChimes.h +++ b/src/displayapp/screens/settings/SettingChimes.h @@ -20,7 +20,7 @@ namespace Pinetime { private: Controllers::Settings& settingsController; uint8_t optionsTotal; - lv_obj_t* cbOption[2]; + lv_obj_t* cbOption[3]; }; } } From 0933d60b1627df18c5615c610b8e26a685901b44 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 13 Mar 2022 21:58:53 +0100 Subject: [PATCH 64/78] Music: fix warning about overridden function Clang warns on `OnTouchEvent()` function, which is overridden, but is missing the `override` keyword ``` In file included from InfiniTime/src/displayapp/screens/Music.cpp:18: InfiniTime/src/displayapp/screens/Music.h:43:14: warning: 'OnTouchEvent' overrides a member function but is not marked 'override' [-Winconsistent-missing-override] bool OnTouchEvent(TouchEvents event); ^ ``` --- src/displayapp/screens/Music.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 35f7bab552..27b2d3d2c5 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -40,7 +40,7 @@ namespace Pinetime { void OnObjectEvent(lv_obj_t* obj, lv_event_t event); private: - bool OnTouchEvent(TouchEvents event); + bool OnTouchEvent(TouchEvents event) override; void UpdateLength(); From 51716898aa00ea2d38dfe38d28a33b4ffbdf22ff Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 13 Mar 2022 22:03:29 +0100 Subject: [PATCH 65/78] Twos: fix warning about extra paranthesis We have a comparison like `if (( a == b ))`, which is a parenthesis too much, which generates the following warning ``` InfiniTime/src/displayapp/screens/Twos.cpp:133:35: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((grid[newRow][newCol].value == grid[oldRow][oldCol].value)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ InfiniTime/src/displayapp/screens/Twos.cpp:133:35: note: remove extraneous parentheses around the comparison to silence this warning if ((grid[newRow][newCol].value == grid[oldRow][oldCol].value)) { ~ ^ ~ ``` --- src/displayapp/screens/Twos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Twos.cpp b/src/displayapp/screens/Twos.cpp index b15332f17b..6d675859c0 100644 --- a/src/displayapp/screens/Twos.cpp +++ b/src/displayapp/screens/Twos.cpp @@ -130,7 +130,7 @@ bool Twos::placeNewTile() { } bool Twos::tryMerge(TwosTile grid[][4], int& newRow, int& newCol, int oldRow, int oldCol) { - if ((grid[newRow][newCol].value == grid[oldRow][oldCol].value)) { + if (grid[newRow][newCol].value == grid[oldRow][oldCol].value) { if ((newCol != oldCol) || (newRow != oldRow)) { if (!grid[newRow][newCol].merged) { unsigned int newVal = grid[oldRow][oldCol].value *= 2; From db41d9081a61b2370a4633568a9cb01bc948a5ab Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 14 Mar 2022 20:28:51 +0100 Subject: [PATCH 66/78] DateTimeController: make possible functions const MonthShortToString and DayOfWeekShortToString don't change the underlying object. Those are just getters and can be declared `const`. --- src/components/datetime/DateTimeController.cpp | 4 ++-- src/components/datetime/DateTimeController.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index e0d124319e..3bfbdc7e7f 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -108,11 +108,11 @@ void DateTime::UpdateTime(uint32_t systickCounter) { } } -const char* DateTime::MonthShortToString() { +const char* DateTime::MonthShortToString() const { return MonthsString[static_cast(month)]; } -const char* DateTime::DayOfWeekShortToString() { +const char* DateTime::DayOfWeekShortToString() const { return DaysStringShort[static_cast(dayOfWeek)]; } diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 6e5ee3caad..00bbc2ee45 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -61,8 +61,8 @@ namespace Pinetime { return second; } - const char* MonthShortToString(); - const char* DayOfWeekShortToString(); + const char* MonthShortToString() const; + const char* DayOfWeekShortToString() const; static const char* MonthShortToStringLow(Months month); std::chrono::time_point CurrentDateTime() const { From bebc072e78145af69aacb1c2c9549da8653b7b0c Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 14 Mar 2022 20:55:20 +0100 Subject: [PATCH 67/78] WatchFaceAnalog: const ref to dateTimeController The clock app only reads from the dateTimeController, never modifies it. --- src/displayapp/screens/WatchFaceAnalog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index a18eb299a2..3377d39e17 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -74,7 +74,7 @@ namespace Pinetime { lv_obj_t* batteryIcon; lv_obj_t* notificationIcon; - Controllers::DateTime& dateTimeController; + const Controllers::DateTime& dateTimeController; Controllers::Battery& batteryController; Controllers::Ble& bleController; Controllers::NotificationManager& notificationManager; From 1379b7902fca8628614af358bac7d546cc94efdc Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 14 Mar 2022 20:33:14 +0100 Subject: [PATCH 68/78] WatchFaceAnalog: local date/time variables Use local date and time variables. No need to store them in the object. --- src/displayapp/screens/WatchFaceAnalog.cpp | 12 ++++++------ src/displayapp/screens/WatchFaceAnalog.h | 7 ------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index f1b9144470..6104281694 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -137,9 +137,9 @@ WatchFaceAnalog::~WatchFaceAnalog() { } void WatchFaceAnalog::UpdateClock() { - hour = dateTimeController.Hours(); - minute = dateTimeController.Minutes(); - second = dateTimeController.Seconds(); + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + uint8_t second = dateTimeController.Seconds(); if (sMinute != minute) { auto const angle = minute * 6; @@ -214,9 +214,9 @@ void WatchFaceAnalog::Refresh() { currentDateTime = dateTimeController.CurrentDateTime(); if (currentDateTime.IsUpdated()) { - month = dateTimeController.Month(); - day = dateTimeController.Day(); - dayOfWeek = dateTimeController.DayOfWeek(); + Pinetime::Controllers::DateTime::Months month = dateTimeController.Month(); + uint8_t day = dateTimeController.Day(); + Pinetime::Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek(); UpdateClock(); diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index a18eb299a2..9412d7390a 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -35,13 +35,6 @@ namespace Pinetime { private: uint8_t sHour, sMinute, sSecond; - uint8_t hour; - uint8_t minute; - uint8_t second; - - Pinetime::Controllers::DateTime::Months month; - uint8_t day; - Pinetime::Controllers::DateTime::Days dayOfWeek; Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; From df61907073fab7d4c2f9595c7771e894a3841b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Mon, 14 Mar 2022 20:44:19 +0100 Subject: [PATCH 69/78] Limit the size of the track and album name received by MusicService. This should work around this bug : https://github.com/InfiniTimeOrg/InfiniTime/issues/825 and prevent heap over-allocation. --- src/components/ble/MusicService.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp index 3457ce4cef..7b74ac2e1b 100644 --- a/src/components/ble/MusicService.cpp +++ b/src/components/ble/MusicService.cpp @@ -47,6 +47,8 @@ namespace { constexpr ble_uuid128_t msRepeatCharUuid {CharUuid(0x0b, 0x00)}; constexpr ble_uuid128_t msShuffleCharUuid {CharUuid(0x0c, 0x00)}; + 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(arg)->OnCommand(conn_handle, attr_handle, ctxt); } @@ -125,6 +127,11 @@ void Pinetime::Controllers::MusicService::Init() { int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); + + if(notifSize > MaxStringSize) { + notifSize = MaxStringSize; + } + char data[notifSize + 1]; data[notifSize] = '\0'; os_mbuf_copydata(ctxt->om, 0, notifSize, data); From f973f1c12c5f82ddacfdaca29fbe1043d94313ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Mon, 14 Mar 2022 21:03:08 +0100 Subject: [PATCH 70/78] Add missing space in if expression. --- src/components/ble/MusicService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp index 7b74ac2e1b..0e53b9cba8 100644 --- a/src/components/ble/MusicService.cpp +++ b/src/components/ble/MusicService.cpp @@ -128,7 +128,7 @@ int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_ if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); - if(notifSize > MaxStringSize) { + if (notifSize > MaxStringSize) { notifSize = MaxStringSize; } From 88197b66328ab8cbecc199c91d1ce1e1688ade83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Thu, 17 Mar 2022 21:15:05 +0100 Subject: [PATCH 71/78] Music app : when title/track name are truncated, add an ellipsis at the end of the strings. --- src/components/ble/MusicService.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp index 0e53b9cba8..c99aa1e36b 100644 --- a/src/components/ble/MusicService.cpp +++ b/src/components/ble/MusicService.cpp @@ -17,6 +17,7 @@ */ #include "components/ble/MusicService.h" #include "systemtask/SystemTask.h" +#include namespace { // 0000yyxx-78fc-48fe-8e23-433b3a1942d0 @@ -127,14 +128,21 @@ void Pinetime::Controllers::MusicService::Init() { int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); - + size_t bufferSize = notifSize; if (notifSize > MaxStringSize) { - notifSize = MaxStringSize; + bufferSize = MaxStringSize; + } + + char data[bufferSize + 1]; + os_mbuf_copydata(ctxt->om, 0, bufferSize, data); + + if (notifSize > bufferSize) { + data[bufferSize-1] = '.'; + data[bufferSize-2] = '.'; + data[bufferSize-3] = '.'; } + data[bufferSize] = '\0'; - char data[notifSize + 1]; - data[notifSize] = '\0'; - os_mbuf_copydata(ctxt->om, 0, notifSize, data); char* s = &data[0]; if (ble_uuid_cmp(ctxt->chr->uuid, &msArtistCharUuid.u) == 0) { artistName = s; From f1194a5f74fa7e02805940a39489210783b94878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Mon, 14 Mar 2022 20:54:04 +0100 Subject: [PATCH 72/78] In current configuration, the timer task (the one from FreeRTOS) has the lowest priority (0). Both display and system tasks are also set on priority 0. In cases where any other task takes too much time to execute (it can happen in Display Task, see https://github.com/InfiniTimeOrg/InfiniTime/issues/825), the timer task does not have the opportunity to run fast enough to detect and debounce presses on the button. This commit sets the following priorities: - [0] : Display Task - [1] : Timer and System tasks - [2] : BLE Host - [3] : BLE LL This way, we ensure that button presses will always be detected, even if the rendering of the display takes a huge amount of time. --- src/FreeRTOSConfig.h | 4 ++-- src/systemtask/SystemTask.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index adbbc8f01e..5462b93cc8 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -60,7 +60,7 @@ #define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */ #define configCPU_CLOCK_HZ (SystemCoreClock) #define configTICK_RATE_HZ 1024 -#define configMAX_PRIORITIES (3) +#define configMAX_PRIORITIES (4) #define configMINIMAL_STACK_SIZE (120) #define configTOTAL_HEAP_SIZE (1024 * 17) #define configMAX_TASK_NAME_LEN (4) @@ -93,7 +93,7 @@ /* Software timer definitions. */ #define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY (0) +#define configTIMER_TASK_PRIORITY (1) #define configTIMER_QUEUE_LENGTH 32 #define configTIMER_TASK_STACK_DEPTH (300) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 1e45fac194..77cf411b4e 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -107,7 +107,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, void SystemTask::Start() { systemTasksMsgQueue = xQueueCreate(10, 1); - if (pdPASS != xTaskCreate(SystemTask::Process, "MAIN", 350, this, 0, &taskHandle)) { + if (pdPASS != xTaskCreate(SystemTask::Process, "MAIN", 350, this, 1, &taskHandle)) { APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); } } From cd1f218dd8710f61238307a9fa5b0d11e229bffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Mon, 14 Mar 2022 21:54:13 +0100 Subject: [PATCH 73/78] Fix priorities of BLE tasks --- .../porting/npl/freertos/src/nimble_port_freertos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c b/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c index b990278100..205831a944 100644 --- a/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c +++ b/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c @@ -38,7 +38,7 @@ nimble_port_freertos_init(TaskFunction_t host_task_fn) * since it has compatible prototype. */ xTaskCreate(nimble_port_ll_task_func, "ll", configMINIMAL_STACK_SIZE + 200, - NULL, configMAX_PRIORITIES - 1, &ll_task_h); + NULL, 3, &ll_task_h); #endif /* @@ -47,5 +47,5 @@ nimble_port_freertos_init(TaskFunction_t host_task_fn) * default queue it is just easier to make separate task which does this. */ xTaskCreate(host_task_fn, "ble", configMINIMAL_STACK_SIZE + 600, - NULL, tskIDLE_PRIORITY + 1, &host_task_h); + NULL, 2, &host_task_h); } From a8b7fbe48b4a86238f38ed0f084b277b44c428fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Thu, 17 Mar 2022 21:22:59 +0100 Subject: [PATCH 74/78] New changes according to the review : Priority 0 for display, 1 for system, timer and ble host, and 2 for ble LL --- src/FreeRTOSConfig.h | 2 +- src/components/ble/NimbleController.cpp | 1 + .../porting/npl/freertos/src/nimble_port_freertos.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 5462b93cc8..263d8031ab 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -60,7 +60,7 @@ #define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 0 /* See into vPortSuppressTicksAndSleep source code for explanation */ #define configCPU_CLOCK_HZ (SystemCoreClock) #define configTICK_RATE_HZ 1024 -#define configMAX_PRIORITIES (4) +#define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) #define configTOTAL_HEAP_SIZE (1024 * 17) #define configMAX_TASK_NAME_LEN (4) diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 0be7c0f7fb..10eb429ae9 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -77,6 +77,7 @@ int GAPEventCallback(struct ble_gap_event* event, void* arg) { void NimbleController::Init() { while (!ble_hs_synced()) { + vTaskDelay(10); } nptr = this; diff --git a/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c b/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c index 205831a944..49834db11a 100644 --- a/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c +++ b/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c @@ -38,7 +38,7 @@ nimble_port_freertos_init(TaskFunction_t host_task_fn) * since it has compatible prototype. */ xTaskCreate(nimble_port_ll_task_func, "ll", configMINIMAL_STACK_SIZE + 200, - NULL, 3, &ll_task_h); + NULL, 2, &ll_task_h); #endif /* @@ -47,5 +47,5 @@ nimble_port_freertos_init(TaskFunction_t host_task_fn) * default queue it is just easier to make separate task which does this. */ xTaskCreate(host_task_fn, "ble", configMINIMAL_STACK_SIZE + 600, - NULL, 2, &host_task_h); + NULL, 1, &host_task_h); } From 4761fcb63a55749c5e46c5fe6bb53ae25b4716c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sun, 27 Mar 2022 20:29:52 +0200 Subject: [PATCH 75/78] DisplayApp : Call the event handler of the current app before loading the new one. This way, we ensure that lv_task_handler() is called before sending event to the newly loaded app. --- src/displayapp/DisplayApp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index fdc6376c5d..c84295638a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -306,14 +306,14 @@ void DisplayApp::Refresh() { } } + if (touchHandler.IsTouching()) { + currentScreen->OnTouchEvent(touchHandler.GetX(), touchHandler.GetY()); + } + if (nextApp != Apps::None) { LoadApp(nextApp, nextDirection); nextApp = Apps::None; } - - if (touchHandler.IsTouching()) { - currentScreen->OnTouchEvent(touchHandler.GetX(), touchHandler.GetY()); - } } void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) { From 8f436e1d74ffdd497c68dc2f34f6a67e430a1932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sun, 27 Mar 2022 20:21:44 +0200 Subject: [PATCH 76/78] Timer App : add background label to ensure that the app will be displayed correctly after a full refresh (HW scrolling transition). Code cleaning and rename methods. --- src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/screens/Timer.cpp | 19 ++++++++++++------- src/displayapp/screens/Timer.h | 27 +++++++++++++++------------ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index c84295638a..f6d2747739 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -207,7 +207,7 @@ void DisplayApp::Refresh() { case Messages::TimerDone: if (currentApp == Apps::Timer) { auto* timer = static_cast(currentScreen.get()); - timer->setDone(); + timer->SetDone(); } else { LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down); } diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index a5e4019522..5cd496c70d 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -1,5 +1,4 @@ #include "displayapp/screens/Timer.h" - #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" #include @@ -7,11 +6,11 @@ using namespace Pinetime::Applications::Screens; static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { - Timer* screen = static_cast(obj->user_data); + auto* screen = static_cast(obj->user_data); screen->OnButtonEvent(obj, event); } -void Timer::createButtons() { +void Timer::CreateButtons() { btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr); btnMinutesUp->user_data = this; lv_obj_set_event_cb(btnMinutesUp, btnEventHandler); @@ -51,6 +50,12 @@ void Timer::createButtons() { Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) : Screen(app), running {true}, timerController {timerController} { + backgroundLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_click(backgroundLabel, true); + lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP); + lv_obj_set_size(backgroundLabel, 240, 240); + lv_obj_set_pos(backgroundLabel, 0, 0); + lv_label_set_text(backgroundLabel, ""); time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); @@ -71,7 +76,7 @@ Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) lv_label_set_text(txtPlayPause, Symbols::pause); } else { lv_label_set_text(txtPlayPause, Symbols::play); - createButtons(); + CreateButtons(); } taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -98,7 +103,7 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { minutesToSet = seconds / 60; secondsToSet = seconds % 60; timerController.StopTimer(); - createButtons(); + CreateButtons(); } else if (secondsToSet + minutesToSet > 0) { lv_label_set_text(txtPlayPause, Symbols::pause); @@ -152,10 +157,10 @@ void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } } -void Timer::setDone() { +void Timer::SetDone() { lv_label_set_text(time, "00:00"); lv_label_set_text(txtPlayPause, Symbols::play); secondsToSet = 0; minutesToSet = 0; - createButtons(); + CreateButtons(); } diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index 23c8734587..93e84c8203 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -8,32 +8,35 @@ #include "components/timer/TimerController.h" namespace Pinetime::Applications::Screens { - class Timer : public Screen { public: enum class Modes { Normal, Done }; Timer(DisplayApp* app, Controllers::TimerController& timerController); - ~Timer() override; - void Refresh() override; - - void setDone(); - + void SetDone(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); private: + void CreateButtons(); bool running; uint8_t secondsToSet = 0; uint8_t minutesToSet = 0; Controllers::TimerController& timerController; - - void createButtons(); - - lv_obj_t *time, *msecTime, *btnPlayPause, *txtPlayPause, *btnMinutesUp, *btnMinutesDown, *btnSecondsUp, *btnSecondsDown, *txtMUp, - *txtMDown, *txtSUp, *txtSDown; - + lv_obj_t* backgroundLabel; + lv_obj_t* time; + lv_obj_t* msecTime; + lv_obj_t* btnPlayPause; + lv_obj_t* txtPlayPause; + lv_obj_t* btnMinutesUp; + lv_obj_t* btnMinutesDown; + lv_obj_t* btnSecondsUp; + lv_obj_t* btnSecondsDown; + lv_obj_t* txtMUp; + lv_obj_t* txtMDown; + lv_obj_t* txtSUp; + lv_obj_t* txtSDown; lv_task_t* taskRefresh; }; } From 78365548f70d9a6ef9a040d8e0039e640e386dc3 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Sat, 2 Apr 2022 16:03:20 +0300 Subject: [PATCH 77/78] Replace airplane mode with a bluetooth toggle --- src/CMakeLists.txt | 2 +- src/components/settings/Settings.h | 2 +- src/displayapp/Apps.h | 2 +- src/displayapp/DisplayApp.cpp | 6 +- src/displayapp/fonts/README.md | 2 +- src/displayapp/fonts/jetbrains_mono_bold_20.c | 72 ++++++++----------- src/displayapp/screens/BleIcon.cpp | 6 +- src/displayapp/screens/BleIcon.h | 2 +- src/displayapp/screens/PineTimeStyle.cpp | 7 +- src/displayapp/screens/Symbols.h | 1 - src/displayapp/screens/WatchFaceDigital.cpp | 2 +- ...gAirplaneMode.cpp => SettingBluetooth.cpp} | 46 ++++++------ ...ttingAirplaneMode.h => SettingBluetooth.h} | 10 +-- src/displayapp/screens/settings/Settings.cpp | 2 +- 14 files changed, 72 insertions(+), 90 deletions(-) rename src/displayapp/screens/settings/{SettingAirplaneMode.cpp => SettingBluetooth.cpp} (68%) rename src/displayapp/screens/settings/{SettingAirplaneMode.h => SettingBluetooth.h} (55%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ff0c9b0cf8..077546a036 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -449,7 +449,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingSetTime.cpp displayapp/screens/settings/SettingChimes.cpp displayapp/screens/settings/SettingShakeThreshold.cpp - displayapp/screens/settings/SettingAirplaneMode.cpp + displayapp/screens/settings/SettingBluetooth.cpp ## Watch faces displayapp/icons/bg_clock.c diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 24a826072f..44a1a85c65 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -237,7 +237,7 @@ namespace Pinetime { uint8_t appMenu = 0; uint8_t settingsMenu = 0; - /* airplaneMode is intentionally not saved with the other watch settings and initialized + /* ble state is intentionally not saved with the other watch settings and initialized * to off (false) on every boot because we always want ble to be enabled on startup */ bool bleRadioEnabled = true; diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index dc9e62536b..8aad953517 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -38,7 +38,7 @@ namespace Pinetime { SettingSetTime, SettingChimes, SettingShakeThreshold, - SettingAirplaneMode, + SettingBluetooth, Error }; } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index f6d2747739..9ce29da653 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -49,7 +49,7 @@ #include "displayapp/screens/settings/SettingSetTime.h" #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" -#include "displayapp/screens/settings/SettingAirplaneMode.h" +#include "displayapp/screens/settings/SettingBluetooth.h" #include "libs/lv_conf.h" @@ -434,8 +434,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentScreen = std::make_unique(this, settingsController, motionController, *systemTask); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; - case Apps::SettingAirplaneMode: - currentScreen = std::make_unique(this, settingsController); + case Apps::SettingBluetooth: + currentScreen = std::make_unique(this, settingsController); ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::BatteryInfo: diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index 7e6203ffb4..c7a8e2bf8a 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -31,7 +31,7 @@ static constexpr const char* newSymbol = "\xEF\x86\x85"; * Do not enable font compression or horizontal subpixel rendering * Load the file `JetBrainsMono-Bold.tff` (use the file in this repo to ensure the version matches) and specify the following range: `0x20-0x7e, 0x410-0x44f` * Add a 2nd font, load the file `FontAwesome5-Solid+Brands+Regular.woff` and specify the following - range: `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf072` + range: `0xf293, 0xf294, 0xf244, 0xf240, 0xf242, 0xf243, 0xf241, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf069, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf029, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015` * Fix an error in the font conversion. Replace the following: diff --git a/src/displayapp/fonts/jetbrains_mono_bold_20.c b/src/displayapp/fonts/jetbrains_mono_bold_20.c index cc67532a32..5c40d4949e 100644 --- a/src/displayapp/fonts/jetbrains_mono_bold_20.c +++ b/src/displayapp/fonts/jetbrains_mono_bold_20.c @@ -840,16 +840,6 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { 0xf8, 0xf, 0x80, 0xf8, 0x3e, 0x0, 0xff, 0xf0, 0x0, 0x3f, 0x80, 0x0, - /* U+F072 "" */ - 0x1, 0xc0, 0x0, 0x7, 0xc0, 0x0, 0x7, 0x80, - 0x0, 0xf, 0x80, 0x0, 0x1f, 0x0, 0x0, 0x1f, - 0x0, 0x38, 0x3e, 0x0, 0x78, 0x7e, 0x0, 0x7f, - 0xff, 0xe0, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf3, - 0xff, 0xff, 0xe7, 0xff, 0xff, 0xdf, 0xff, 0xfc, - 0x3c, 0x3f, 0x0, 0x70, 0x7c, 0x0, 0x1, 0xf0, - 0x0, 0x3, 0xe0, 0x0, 0x7, 0x80, 0x0, 0xf, - 0x0, 0x0, 0x1c, 0x0, 0x0, - /* U+F095 "" */ 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x7, 0xf0, 0x0, 0x7f, 0x0, 0x7, 0xf0, 0x0, 0xff, 0x0, @@ -1230,32 +1220,31 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { {.bitmap_index = 3027, .adv_w = 280, .box_w = 13, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, {.bitmap_index = 3055, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, {.bitmap_index = 3103, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 3147, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3208, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3261, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3280, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3330, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3366, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3414, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 3454, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3497, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3535, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3573, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3611, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3649, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 3687, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3723, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, - {.bitmap_index = 3761, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3790, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 3828, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 3894, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 3943, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 3993, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4053, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 4106, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, - {.bitmap_index = 4167, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4222, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 4275, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} + {.bitmap_index = 3147, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3200, .adv_w = 120, .box_w = 8, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3219, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3269, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3305, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3353, .adv_w = 320, .box_w = 21, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3393, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3436, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3474, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3512, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3550, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3588, .adv_w = 400, .box_w = 25, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 3626, .adv_w = 240, .box_w = 15, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3662, .adv_w = 280, .box_w = 15, .box_h = 20, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3700, .adv_w = 200, .box_w = 11, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3729, .adv_w = 280, .box_w = 16, .box_h = 19, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 3767, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3833, .adv_w = 360, .box_w = 23, .box_h = 17, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3882, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3932, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3992, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4045, .adv_w = 360, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4106, .adv_w = 360, .box_w = 22, .box_h = 20, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4161, .adv_w = 360, .box_w = 22, .box_h = 19, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4214, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0} }; /*--------------------- @@ -1264,11 +1253,10 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { static const uint16_t unicode_list_2[] = { 0x0, 0x14, 0x16, 0x23, 0x26, 0x27, 0x28, 0x39, - 0x47, 0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x6d, 0x71, - 0x94, 0x128, 0x184, 0x1e5, 0x1fb, 0x200, 0x21d, 0x23f, - 0x240, 0x241, 0x242, 0x243, 0x251, 0x292, 0x293, 0x2f1, - 0x3dc, 0x3fc, 0x45c, 0x54a, 0x55f, 0x568, 0x59e, 0x59f, - 0x6a8 + 0x47, 0x4a, 0x4b, 0x4c, 0x50, 0x68, 0x6d, 0x94, + 0x128, 0x184, 0x1e5, 0x1fb, 0x200, 0x21d, 0x23f, 0x240, + 0x241, 0x242, 0x243, 0x251, 0x292, 0x293, 0x2f1, 0x3dc, + 0x3fc, 0x45c, 0x54a, 0x55f, 0x568, 0x59e, 0x59f, 0x6a8 }; /*Collect the unicode lists and glyph_id offsets*/ @@ -1284,7 +1272,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] = }, { .range_start = 61441, .range_length = 1705, .glyph_id_start = 160, - .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 41, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY + .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 40, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY } }; diff --git a/src/displayapp/screens/BleIcon.cpp b/src/displayapp/screens/BleIcon.cpp index 019f80397f..780a14cfff 100644 --- a/src/displayapp/screens/BleIcon.cpp +++ b/src/displayapp/screens/BleIcon.cpp @@ -2,11 +2,7 @@ #include "displayapp/screens/Symbols.h" using namespace Pinetime::Applications::Screens; -const char* BleIcon::GetIcon(bool isRadioEnabled, bool isConnected) { - if(!isRadioEnabled) { - return Symbols::airplane; - } - +const char* BleIcon::GetIcon(bool isConnected) { if (isConnected) { return Symbols::bluetooth; } diff --git a/src/displayapp/screens/BleIcon.h b/src/displayapp/screens/BleIcon.h index d32dfad7ee..d9a46541b0 100644 --- a/src/displayapp/screens/BleIcon.h +++ b/src/displayapp/screens/BleIcon.h @@ -7,7 +7,7 @@ namespace Pinetime { namespace Screens { class BleIcon { public: - static const char* GetIcon(bool isRadioEnabled, bool isConnected); + static const char* GetIcon(bool isConnected); }; } } diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp index 44bf47a4f5..e807289cf9 100644 --- a/src/displayapp/screens/PineTimeStyle.cpp +++ b/src/displayapp/screens/PineTimeStyle.cpp @@ -345,11 +345,10 @@ void PineTimeStyle::SetBatteryIcon() { void PineTimeStyle::AlignIcons() { - bool isBleIconVisible = IsBleIconVisible(bleRadioEnabled.Get(), bleState.Get()); - if (notificationState.Get() && isBleIconVisible) { + if (notificationState.Get() && bleState.Get()) { lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 8, 25); lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, -8, 25); - } else if (notificationState.Get() && !isBleIconVisible) { + } else if (notificationState.Get() && !bleState.Get()) { lv_obj_align(notificationIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); } else { lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 25); @@ -375,7 +374,7 @@ void PineTimeStyle::Refresh() { bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(bleRadioEnabled.Get(), bleState.Get())); + lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); AlignIcons(); } diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 5ba8f95352..e68a7af6b2 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -44,7 +44,6 @@ namespace Pinetime { static constexpr const char* chartLine = "\xEF\x88\x81"; static constexpr const char* eye = "\xEF\x81\xAE"; static constexpr const char* home = "\xEF\x80\x95"; - static constexpr const char* airplane = "\xEF\x81\xB2"; // lv_font_sys_48.c static constexpr const char* settings = "\xEE\xA4\x82"; // e902 diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 59bde83996..6a9148847c 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -121,7 +121,7 @@ void WatchFaceDigital::Refresh() { bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(bleRadioEnabled.Get(), bleState.Get())); + lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); } lv_obj_realign(batteryIcon); lv_obj_realign(batteryPlug); diff --git a/src/displayapp/screens/settings/SettingAirplaneMode.cpp b/src/displayapp/screens/settings/SettingBluetooth.cpp similarity index 68% rename from src/displayapp/screens/settings/SettingAirplaneMode.cpp rename to src/displayapp/screens/settings/SettingBluetooth.cpp index 85172787b4..ab1af223f5 100644 --- a/src/displayapp/screens/settings/SettingAirplaneMode.cpp +++ b/src/displayapp/screens/settings/SettingBluetooth.cpp @@ -1,4 +1,4 @@ -#include "displayapp/screens/settings/SettingAirplaneMode.h" +#include "displayapp/screens/settings/SettingBluetooth.h" #include #include "displayapp/DisplayApp.h" #include "displayapp/Messages.h" @@ -9,18 +9,18 @@ using namespace Pinetime::Applications::Screens; namespace { - static void OnAirplaneModeEnabledEvent(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast(obj->user_data); - screen->OnAirplaneModeEnabled(obj, event); + static void OnBluetoothDisabledEvent(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnBluetoothDisabled(obj, event); } - static void OnAirplaneModeDisabledEvent(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast(obj->user_data); - screen->OnAirplaneModeDisabled(obj, event); + static void OnBluetoothEnabledEvent(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnBluetoothEnabled(obj, event); } } -SettingAirplaneMode::SettingAirplaneMode(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) +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); @@ -36,38 +36,38 @@ SettingAirplaneMode::SettingAirplaneMode(Pinetime::Applications::DisplayApp* app 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, "Airplane mode"); + 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::airplane); + 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, " Enable"); + lv_checkbox_set_text(cbEnabled, " Enabled"); cbEnabled->user_data = this; - lv_obj_set_event_cb(cbEnabled, OnAirplaneModeEnabledEvent); + lv_obj_set_event_cb(cbEnabled, OnBluetoothEnabledEvent); SetRadioButtonStyle(cbEnabled); cbDisabled = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbDisabled, " Disable"); + lv_checkbox_set_text(cbDisabled, " Disabled"); cbDisabled->user_data = this; - lv_obj_set_event_cb(cbDisabled, OnAirplaneModeDisabledEvent); + lv_obj_set_event_cb(cbDisabled, OnBluetoothDisabledEvent); SetRadioButtonStyle(cbDisabled); if (settingsController.GetBleRadioEnabled()) { - lv_checkbox_set_checked(cbDisabled, true); + lv_checkbox_set_checked(cbEnabled, true); priorMode = true; } else { - lv_checkbox_set_checked(cbEnabled, true); + lv_checkbox_set_checked(cbDisabled, true); priorMode = false; } } -SettingAirplaneMode::~SettingAirplaneMode() { +SettingBluetooth::~SettingBluetooth() { lv_obj_clean(lv_scr_act()); // Do not call SaveSettings - see src/components/settings/Settings.h if (priorMode != settingsController.GetBleRadioEnabled()) { @@ -75,18 +75,18 @@ SettingAirplaneMode::~SettingAirplaneMode() { } } -void SettingAirplaneMode::OnAirplaneModeEnabled(lv_obj_t* object, lv_event_t event) { +void SettingBluetooth::OnBluetoothDisabled(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); + lv_checkbox_set_checked(cbEnabled, false); + lv_checkbox_set_checked(cbDisabled, true); settingsController.SetBleRadioEnabled(false); } } -void SettingAirplaneMode::OnAirplaneModeDisabled(lv_obj_t* object, lv_event_t event) { +void SettingBluetooth::OnBluetoothEnabled(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); + lv_checkbox_set_checked(cbEnabled, true); + lv_checkbox_set_checked(cbDisabled, false); settingsController.SetBleRadioEnabled(true); } } diff --git a/src/displayapp/screens/settings/SettingAirplaneMode.h b/src/displayapp/screens/settings/SettingBluetooth.h similarity index 55% rename from src/displayapp/screens/settings/SettingAirplaneMode.h rename to src/displayapp/screens/settings/SettingBluetooth.h index b3478c64fd..12bb459aa0 100644 --- a/src/displayapp/screens/settings/SettingAirplaneMode.h +++ b/src/displayapp/screens/settings/SettingBluetooth.h @@ -12,13 +12,13 @@ namespace Pinetime { namespace Applications { namespace Screens { - class SettingAirplaneMode : public Screen { + class SettingBluetooth : public Screen { public: - SettingAirplaneMode(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); - ~SettingAirplaneMode() override; + SettingBluetooth(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); + ~SettingBluetooth() override; - void OnAirplaneModeEnabled(lv_obj_t* object, lv_event_t event); - void OnAirplaneModeDisabled(lv_obj_t* object, lv_event_t event); + void OnBluetoothEnabled(lv_obj_t* object, lv_event_t event); + void OnBluetoothDisabled(lv_obj_t* object, lv_event_t event); private: Controllers::Settings& settingsController; diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp index dce0c0714a..bc7efcc292 100644 --- a/src/displayapp/screens/settings/Settings.cpp +++ b/src/displayapp/screens/settings/Settings.cpp @@ -64,7 +64,7 @@ std::unique_ptr Settings::CreateScreen3() { {Symbols::clock, "Chimes", Apps::SettingChimes}, {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, - {Symbols::airplane, "Airplane mode", Apps::SettingAirplaneMode} + {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth} }}; return std::make_unique(2, 4, app, settingsController, applications); From b498e1d633522eed975d78b04508834b7a79befe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sat, 2 Apr 2022 16:31:39 +0200 Subject: [PATCH 78/78] Set version to 1.9.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8846531e8c..55b68bc73e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(pinetime VERSION 1.8.0 LANGUAGES C CXX ASM) +project(pinetime VERSION 1.9.0 LANGUAGES C CXX ASM) set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 14)