aboutsummaryrefslogtreecommitdiffstats
path: root/src/displayapp
diff options
context:
space:
mode:
Diffstat (limited to 'src/displayapp')
-rw-r--r--src/displayapp/Apps.h43
-rw-r--r--src/displayapp/Controllers.h56
-rw-r--r--src/displayapp/DisplayApp.cpp363
-rw-r--r--src/displayapp/DisplayApp.h34
-rw-r--r--src/displayapp/DisplayAppRecovery.cpp26
-rw-r--r--src/displayapp/DisplayAppRecovery.h15
-rw-r--r--src/displayapp/LittleVgl.cpp14
-rw-r--r--src/displayapp/LittleVgl.h1
-rw-r--r--src/displayapp/Messages.h9
-rw-r--r--src/displayapp/UserApps.h60
-rw-r--r--src/displayapp/apps/Apps.h.in80
-rw-r--r--src/displayapp/apps/CMakeLists.txt39
-rw-r--r--src/displayapp/fonts/CMakeLists.txt5
-rw-r--r--src/displayapp/fonts/README.md16
-rw-r--r--src/displayapp/fonts/fonts.json19
-rwxr-xr-xsrc/displayapp/fonts/generate.py2
-rw-r--r--src/displayapp/icons/bg_clock.c272
-rw-r--r--src/displayapp/screens/Alarm.cpp48
-rw-r--r--src/displayapp/screens/Alarm.h33
-rw-r--r--src/displayapp/screens/ApplicationList.cpp29
-rw-r--r--src/displayapp/screens/ApplicationList.h42
-rw-r--r--src/displayapp/screens/BatteryInfo.cpp43
-rw-r--r--src/displayapp/screens/BatteryInfo.h2
-rw-r--r--src/displayapp/screens/Calculator.cpp375
-rw-r--r--src/displayapp/screens/Calculator.h83
-rw-r--r--src/displayapp/screens/CheckboxList.h2
-rw-r--r--src/displayapp/screens/Clock.cpp129
-rw-r--r--src/displayapp/screens/Clock.h57
-rw-r--r--src/displayapp/screens/Dice.cpp199
-rw-r--r--src/displayapp/screens/Dice.h61
-rw-r--r--src/displayapp/screens/FirmwareUpdate.cpp6
-rw-r--r--src/displayapp/screens/FirmwareValidation.cpp4
-rw-r--r--src/displayapp/screens/FlashLight.cpp7
-rw-r--r--src/displayapp/screens/FlashLight.h4
-rw-r--r--src/displayapp/screens/HeartRate.cpp19
-rw-r--r--src/displayapp/screens/HeartRate.h14
-rw-r--r--src/displayapp/screens/InfiniPaint.h13
-rw-r--r--src/displayapp/screens/List.h2
-rw-r--r--src/displayapp/screens/Metronome.cpp7
-rw-r--r--src/displayapp/screens/Metronome.h14
-rw-r--r--src/displayapp/screens/Motion.cpp8
-rw-r--r--src/displayapp/screens/Motion.h12
-rw-r--r--src/displayapp/screens/Music.h13
-rw-r--r--src/displayapp/screens/Navigation.cpp289
-rw-r--r--src/displayapp/screens/Navigation.h19
-rw-r--r--src/displayapp/screens/Notifications.cpp20
-rw-r--r--src/displayapp/screens/Notifications.h3
-rw-r--r--src/displayapp/screens/Paddle.h13
-rw-r--r--src/displayapp/screens/Screen.h35
-rw-r--r--src/displayapp/screens/Steps.h13
-rw-r--r--src/displayapp/screens/StopWatch.cpp37
-rw-r--r--src/displayapp/screens/StopWatch.h90
-rw-r--r--src/displayapp/screens/Symbols.h16
-rw-r--r--src/displayapp/screens/SystemInfo.cpp70
-rw-r--r--src/displayapp/screens/SystemInfo.h5
-rw-r--r--src/displayapp/screens/Tile.cpp9
-rw-r--r--src/displayapp/screens/Tile.h4
-rw-r--r--src/displayapp/screens/Timer.cpp37
-rw-r--r--src/displayapp/screens/Timer.h73
-rw-r--r--src/displayapp/screens/Twos.cpp2
-rw-r--r--src/displayapp/screens/Twos.h13
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.cpp42
-rw-r--r--src/displayapp/screens/WatchFaceAnalog.h41
-rw-r--r--src/displayapp/screens/WatchFaceCasioStyleG7710.cpp79
-rw-r--r--src/displayapp/screens/WatchFaceCasioStyleG7710.h54
-rw-r--r--src/displayapp/screens/WatchFaceDigital.cpp100
-rw-r--r--src/displayapp/screens/WatchFaceDigital.h54
-rw-r--r--src/displayapp/screens/WatchFaceInfineat.cpp73
-rw-r--r--src/displayapp/screens/WatchFaceInfineat.h46
-rw-r--r--src/displayapp/screens/WatchFacePineTimeStyle.cpp147
-rw-r--r--src/displayapp/screens/WatchFacePineTimeStyle.h49
-rw-r--r--src/displayapp/screens/WatchFaceTerminal.cpp57
-rw-r--r--src/displayapp/screens/WatchFaceTerminal.h51
-rw-r--r--src/displayapp/screens/Weather.cpp376
-rw-r--r--src/displayapp/screens/Weather.h59
-rw-r--r--src/displayapp/screens/WeatherSymbols.cpp61
-rw-r--r--src/displayapp/screens/WeatherSymbols.h14
-rw-r--r--src/displayapp/screens/settings/QuickSettings.cpp5
-rw-r--r--src/displayapp/screens/settings/QuickSettings.h3
-rw-r--r--src/displayapp/screens/settings/SettingBluetooth.cpp6
-rw-r--r--src/displayapp/screens/settings/SettingBluetooth.h1
-rw-r--r--src/displayapp/screens/settings/SettingDisplay.cpp31
-rw-r--r--src/displayapp/screens/settings/SettingDisplay.h5
-rw-r--r--src/displayapp/screens/settings/SettingSetDateTime.cpp3
-rw-r--r--src/displayapp/screens/settings/SettingSetDateTime.h1
-rw-r--r--src/displayapp/screens/settings/SettingWakeUp.cpp6
-rw-r--r--src/displayapp/screens/settings/SettingWakeUp.h3
-rw-r--r--src/displayapp/screens/settings/SettingWatchFace.cpp47
-rw-r--r--src/displayapp/screens/settings/SettingWatchFace.h30
-rw-r--r--src/displayapp/screens/settings/SettingWeatherFormat.cpp63
-rw-r--r--src/displayapp/screens/settings/SettingWeatherFormat.h26
-rw-r--r--src/displayapp/screens/settings/Settings.cpp2
-rw-r--r--src/displayapp/screens/settings/Settings.h8
-rw-r--r--src/displayapp/widgets/StatusIcons.cpp15
-rw-r--r--src/displayapp/widgets/StatusIcons.h17
95 files changed, 2993 insertions, 1610 deletions
diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h
deleted file mode 100644
index f253bc03..00000000
--- a/src/displayapp/Apps.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-namespace Pinetime {
- namespace Applications {
- enum class Apps {
- None,
- Launcher,
- Clock,
- SysInfo,
- FirmwareUpdate,
- FirmwareValidation,
- NotificationsPreview,
- Notifications,
- Timer,
- Alarm,
- FlashLight,
- BatteryInfo,
- Music,
- Paint,
- Paddle,
- Twos,
- HeartRate,
- Navigation,
- StopWatch,
- Metronome,
- Motion,
- Steps,
- PassKey,
- QuickSettings,
- Settings,
- SettingWatchFace,
- SettingTimeFormat,
- SettingDisplay,
- SettingWakeUp,
- SettingSteps,
- SettingSetDateTime,
- SettingChimes,
- SettingShakeThreshold,
- SettingBluetooth,
- Error
- };
- }
-}
diff --git a/src/displayapp/Controllers.h b/src/displayapp/Controllers.h
new file mode 100644
index 00000000..9992426c
--- /dev/null
+++ b/src/displayapp/Controllers.h
@@ -0,0 +1,56 @@
+#pragma once
+
+namespace Pinetime {
+ namespace Applications {
+ class DisplayApp;
+ }
+
+ namespace Components {
+ class LittleVgl;
+ }
+
+ namespace Controllers {
+ class Battery;
+ class Ble;
+ class DateTime;
+ class NotificationManager;
+ class HeartRateController;
+ class Settings;
+ class MotorController;
+ class MotionController;
+ class AlarmController;
+ class BrightnessController;
+ class SimpleWeatherService;
+ class FS;
+ class Timer;
+ class MusicService;
+ class NavigationService;
+ }
+
+ namespace System {
+ class SystemTask;
+ }
+
+ namespace Applications {
+ struct AppControllers {
+ const Pinetime::Controllers::Battery& batteryController;
+ const Pinetime::Controllers::Ble& bleController;
+ Pinetime::Controllers::DateTime& dateTimeController;
+ Pinetime::Controllers::NotificationManager& notificationManager;
+ Pinetime::Controllers::HeartRateController& heartRateController;
+ Pinetime::Controllers::Settings& settingsController;
+ Pinetime::Controllers::MotorController& motorController;
+ Pinetime::Controllers::MotionController& motionController;
+ Pinetime::Controllers::AlarmController& alarmController;
+ Pinetime::Controllers::BrightnessController& brightnessController;
+ Pinetime::Controllers::SimpleWeatherService* weatherController;
+ Pinetime::Controllers::FS& filesystem;
+ Pinetime::Controllers::Timer& timer;
+ Pinetime::System::SystemTask* systemTask;
+ Pinetime::Applications::DisplayApp* displayApp;
+ Pinetime::Components::LittleVgl& lvgl;
+ Pinetime::Controllers::MusicService* musicService;
+ Pinetime::Controllers::NavigationService* navigationService;
+ };
+ }
+}
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index ccba7ee6..add00650 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -11,7 +11,6 @@
#include "components/motion/MotionController.h"
#include "components/motor/MotorController.h"
#include "displayapp/screens/ApplicationList.h"
-#include "displayapp/screens/Clock.h"
#include "displayapp/screens/FirmwareUpdate.h"
#include "displayapp/screens/FirmwareValidation.h"
#include "displayapp/screens/InfiniPaint.h"
@@ -27,8 +26,11 @@
#include "displayapp/screens/FlashLight.h"
#include "displayapp/screens/BatteryInfo.h"
#include "displayapp/screens/Steps.h"
+#include "displayapp/screens/Dice.h"
+#include "displayapp/screens/Weather.h"
#include "displayapp/screens/PassKey.h"
#include "displayapp/screens/Error.h"
+#include "displayapp/screens/Calculator.h"
#include "drivers/Cst816s.h"
#include "drivers/St7789.h"
@@ -40,6 +42,7 @@
#include "displayapp/screens/settings/Settings.h"
#include "displayapp/screens/settings/SettingWatchFace.h"
#include "displayapp/screens/settings/SettingTimeFormat.h"
+#include "displayapp/screens/settings/SettingWeatherFormat.h"
#include "displayapp/screens/settings/SettingWakeUp.h"
#include "displayapp/screens/settings/SettingDisplay.h"
#include "displayapp/screens/settings/SettingSteps.h"
@@ -49,6 +52,7 @@
#include "displayapp/screens/settings/SettingBluetooth.h"
#include "libs/lv_conf.h"
+#include "UserApps.h"
using namespace Pinetime::Applications;
using namespace Pinetime::Applications::Display;
@@ -57,6 +61,11 @@ namespace {
inline bool in_isr() {
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
}
+
+ void TimerCallback(TimerHandle_t xTimer) {
+ auto* dispApp = static_cast<DisplayApp*>(pvTimerGetTimerID(xTimer));
+ dispApp->PushMessage(Display::Messages::TimerDone);
+ }
}
DisplayApp::DisplayApp(Drivers::St7789& lcd,
@@ -70,11 +79,11 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
Controllers::Settings& settingsController,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
- Pinetime::Controllers::TimerController& timerController,
Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::TouchHandler& touchHandler,
- Pinetime::Controllers::FS& filesystem)
+ Pinetime::Controllers::FS& filesystem,
+ Pinetime::Drivers::SpiNorFlash& spiNorFlash)
: lcd {lcd},
touchPanel {touchPanel},
batteryController {batteryController},
@@ -86,12 +95,31 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
settingsController {settingsController},
motorController {motorController},
motionController {motionController},
- timerController {timerController},
alarmController {alarmController},
brightnessController {brightnessController},
touchHandler {touchHandler},
filesystem {filesystem},
- lvgl {lcd, filesystem} {
+ spiNorFlash {spiNorFlash},
+ lvgl {lcd, filesystem},
+ timer(this, TimerCallback),
+ controllers {batteryController,
+ bleController,
+ dateTimeController,
+ notificationManager,
+ heartRateController,
+ settingsController,
+ motorController,
+ motionController,
+ alarmController,
+ brightnessController,
+ nullptr,
+ filesystem,
+ timer,
+ nullptr,
+ this,
+ lvgl,
+ nullptr,
+ nullptr} {
}
void DisplayApp::Start(System::BootErrors error) {
@@ -100,6 +128,7 @@ void DisplayApp::Start(System::BootErrors error) {
bootError = error;
lvgl.Init();
+ motorController.Init();
if (error == System::BootErrors::TouchController) {
LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None);
@@ -117,9 +146,6 @@ void DisplayApp::Process(void* instance) {
NRF_LOG_INFO("displayapp task started!");
app->InitHw();
- // Send a dummy notification to unlock the lvgl display driver for the first iteration
- xTaskNotifyGive(xTaskGetCurrentTaskHandle());
-
while (true) {
app->Refresh();
}
@@ -128,10 +154,47 @@ void DisplayApp::Process(void* instance) {
void DisplayApp::InitHw() {
brightnessController.Init();
ApplyBrightness();
- motorController.Init();
lcd.Init();
}
+TickType_t DisplayApp::CalculateSleepTime() {
+ // Calculates how many system ticks DisplayApp should sleep before rendering the next AOD frame
+ // Next frame time is frame count * refresh period (ms) * tick rate
+
+ auto RoundedDiv = [](uint32_t a, uint32_t b) {
+ return ((a + (b / 2)) / b);
+ };
+ // RoundedDiv overflows when numerator + (denominator floordiv 2) > uint32 max
+ // in this case around 9 hours (=overflow frame count / always on refresh period)
+ constexpr TickType_t overflowFrameCount = (UINT32_MAX - (1000 / 16)) / ((configTICK_RATE_HZ / 8) * alwaysOnRefreshPeriod);
+
+ TickType_t ticksElapsed = xTaskGetTickCount() - alwaysOnStartTime;
+ // Divide both the numerator and denominator by 8 (=GCD(1000,1024))
+ // to increase the number of ticks (frames) before the overflow tick is reached
+ TickType_t targetRenderTick = RoundedDiv((configTICK_RATE_HZ / 8) * alwaysOnFrameCount * alwaysOnRefreshPeriod, 1000 / 8);
+
+ // Assumptions
+
+ // Tick rate is multiple of 8
+ // Needed for division trick above
+ static_assert(configTICK_RATE_HZ % 8 == 0);
+
+ // Frame count must always wraparound more often than the system tick count does
+ // Always on overflow time (ms) < system tick overflow time (ms)
+ // Using 64bit ints here to avoid overflow
+ static_assert((uint64_t) overflowFrameCount * (uint64_t) alwaysOnRefreshPeriod < (uint64_t) UINT32_MAX * 1000ULL / configTICK_RATE_HZ);
+
+ if (alwaysOnFrameCount == overflowFrameCount) {
+ alwaysOnFrameCount = 0;
+ alwaysOnStartTime = xTaskGetTickCount();
+ }
+ if (targetRenderTick > ticksElapsed) {
+ return targetRenderTick - ticksElapsed;
+ } else {
+ return 0;
+ }
+}
+
void DisplayApp::Refresh() {
auto LoadPreviousScreen = [this]() {
FullRefreshDirections returnDirection;
@@ -155,16 +218,70 @@ void DisplayApp::Refresh() {
LoadScreen(returnAppStack.Pop(), returnDirection);
};
+ auto IsPastDimTime = [this]() -> bool {
+ return lv_disp_get_inactive_time(nullptr) >= pdMS_TO_TICKS(settingsController.GetScreenTimeOut() - 2000);
+ };
+
+ auto IsPastSleepTime = [this]() -> bool {
+ return lv_disp_get_inactive_time(nullptr) >= pdMS_TO_TICKS(settingsController.GetScreenTimeOut());
+ };
+
TickType_t queueTimeout;
switch (state) {
case States::Idle:
queueTimeout = portMAX_DELAY;
break;
+ case States::AOD:
+ if (!currentScreen->IsRunning()) {
+ LoadPreviousScreen();
+ }
+ // Check we've slept long enough
+ // Might not be true if the loop received an event
+ // If not true, then wait that amount of time
+ queueTimeout = CalculateSleepTime();
+ if (queueTimeout == 0) {
+ // Only advance the tick count when LVGL is done
+ // Otherwise keep running the task handler while it still has things to draw
+ // Note: under high graphics load, LVGL will always have more work to do
+ if (lv_task_handler() > 0) {
+ // Drop frames that we've missed if drawing/event handling took way longer than expected
+ while (queueTimeout == 0) {
+ alwaysOnFrameCount += 1;
+ queueTimeout = CalculateSleepTime();
+ }
+ }
+ }
+ break;
case States::Running:
if (!currentScreen->IsRunning()) {
LoadPreviousScreen();
}
queueTimeout = lv_task_handler();
+
+ if (!systemTask->IsSleepDisabled() && IsPastDimTime()) {
+ if (!isDimmed) {
+ isDimmed = true;
+ brightnessController.Set(Controllers::BrightnessController::Levels::Low);
+ }
+ if (IsPastSleepTime() && uxQueueMessagesWaiting(msgQueue) == 0) {
+ PushMessageToSystemTask(System::Messages::GoToSleep);
+ // Can't set state to Idle here, something may send
+ // DisableSleeping before this GoToSleep arrives
+ // Instead we check we have no messages queued before sending GoToSleep
+ // This works as the SystemTask is higher priority than DisplayApp
+ // As soon as we send GoToSleep, SystemTask pre-empts DisplayApp
+ // Whenever DisplayApp is running again, it is guaranteed that
+ // SystemTask has handled the message
+ // If it responded, we will have a GoToSleep waiting in the queue
+ // By checking that there are no messages in the queue, we avoid
+ // resending GoToSleep when we already have a response
+ // SystemTask is resilient to duplicate messages, this is an
+ // optimisation to reduce pressure on the message queues
+ }
+ } else if (isDimmed) {
+ isDimmed = false;
+ ApplyBrightness();
+ }
break;
default:
queueTimeout = portMAX_DELAY;
@@ -174,38 +291,83 @@ void DisplayApp::Refresh() {
Messages msg;
if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) {
switch (msg) {
- case Messages::DimScreen:
- brightnessController.Set(Controllers::BrightnessController::Levels::Low);
- break;
- case Messages::RestoreBrightness:
- ApplyBrightness();
- break;
case Messages::GoToSleep:
- while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
+ case Messages::GoToAOD:
+ // Checking if SystemTask is sleeping is purely an optimisation.
+ // If it's no longer sleeping since it sent GoToSleep, it has
+ // cancelled the sleep and transitioned directly from
+ // GoingToSleep->Running, so we are about to receive GoToRunning
+ // and can ignore this message. If it wasn't ignored, DisplayApp
+ // would go to sleep and then immediately re-wake
+ if (state != States::Running || !systemTask->IsSleeping()) {
+ break;
+ }
+ while (brightnessController.Level() != Controllers::BrightnessController::Levels::Low) {
brightnessController.Lower();
vTaskDelay(100);
}
- lcd.Sleep();
- PushMessageToSystemTask(Pinetime::System::Messages::OnDisplayTaskSleeping);
- state = States::Idle;
+ // Turn brightness down (or set to AlwaysOn mode)
+ if (msg == Messages::GoToAOD) {
+ brightnessController.Set(Controllers::BrightnessController::Levels::AlwaysOn);
+ } else {
+ brightnessController.Set(Controllers::BrightnessController::Levels::Off);
+ }
+ // Since the active screen is not really an app, go back to Clock.
+ if (currentApp == Apps::Launcher || currentApp == Apps::Notifications || currentApp == Apps::QuickSettings ||
+ currentApp == Apps::Settings) {
+ LoadScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
+ // Wait for the clock app to load before moving on.
+ while (!lv_task_handler()) {
+ };
+ }
+ // Clear any ongoing touch pressed events
+ // Without this LVGL gets stuck in the pressed state and will keep refreshing the
+ // display activity timer causing the screen to never sleep after timeout
+ lvgl.ClearTouchState();
+ if (msg == Messages::GoToAOD) {
+ lcd.LowPowerOn();
+ // Record idle entry time
+ alwaysOnFrameCount = 0;
+ alwaysOnStartTime = xTaskGetTickCount();
+ PushMessageToSystemTask(Pinetime::System::Messages::OnDisplayTaskAOD);
+ state = States::AOD;
+ } else {
+ lcd.Sleep();
+ PushMessageToSystemTask(Pinetime::System::Messages::OnDisplayTaskSleeping);
+ state = States::Idle;
+ }
+ break;
+ case Messages::NotifyDeviceActivity:
+ lv_disp_trig_activity(nullptr);
break;
case Messages::GoToRunning:
- lcd.Wakeup();
+ // If SystemTask is sleeping, the GoToRunning message is old
+ // and must be ignored. Otherwise DisplayApp will use SPI
+ // that is powered down and cause bad behaviour
+ if (state == States::Running || systemTask->IsSleeping()) {
+ break;
+ }
+ if (state == States::AOD) {
+ lcd.LowPowerOff();
+ } else {
+ lcd.Wakeup();
+ }
+ lv_disp_trig_activity(nullptr);
ApplyBrightness();
state = States::Running;
break;
- case Messages::UpdateTimeOut:
- PushMessageToSystemTask(System::Messages::UpdateTimeOut);
- break;
case Messages::UpdateBleConnection:
- // clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
- // Screens::Clock::BleConnectionStates::NotConnected);
+ // Only used for recovery firmware
break;
case Messages::NewNotification:
LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
break;
case Messages::TimerDone:
+ if (state != States::Running) {
+ PushMessageToSystemTask(System::Messages::GoToRunning);
+ }
if (currentApp == Apps::Timer) {
+ lv_disp_trig_activity(nullptr);
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
timer->Reset();
} else {
@@ -310,21 +472,14 @@ void DisplayApp::Refresh() {
case Messages::BleRadioEnableToggle:
PushMessageToSystemTask(System::Messages::BleRadioEnableToggle);
break;
- case Messages::UpdateDateTime:
- // Added to remove warning
- // What should happen here?
- break;
case Messages::Chime:
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
motorController.RunForDuration(35);
break;
- case Messages::OnChargingEvent:
- motorController.RunForDuration(15);
- break;
}
}
- if (touchHandler.IsTouching()) {
+ if (state == States::Running && touchHandler.IsTouching()) {
currentScreen->OnTouchEvent(touchHandler.GetX(), touchHandler.GetY());
}
@@ -352,32 +507,40 @@ void DisplayApp::LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direc
void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction) {
lvgl.CancelTap();
- ApplyBrightness();
+ lv_disp_trig_activity(nullptr);
motorController.StopRinging();
currentScreen.reset(nullptr);
SetFullRefresh(direction);
switch (app) {
- case Apps::Launcher:
- currentScreen =
- std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, bleController, dateTimeController);
- break;
- case Apps::Motion:
- // currentScreen = std::make_unique<Screens::Motion>(motionController);
- // break;
- case Apps::None:
- case Apps::Clock:
- currentScreen = std::make_unique<Screens::Clock>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController,
- heartRateController,
- motionController,
- filesystem);
- break;
-
+ case Apps::Launcher: {
+ std::array<Screens::Tile::Applications, UserAppTypes::Count> apps;
+ int i = 0;
+ for (const auto& userApp : userApps) {
+ apps[i++] = Screens::Tile::Applications {userApp.icon, userApp.app, true};
+ }
+ currentScreen = std::make_unique<Screens::ApplicationList>(this,
+ settingsController,
+ batteryController,
+ bleController,
+ alarmController,
+ dateTimeController,
+ filesystem,
+ std::move(apps));
+ } break;
+ case Apps::Clock: {
+ const auto* watchFace =
+ std::find_if(userWatchFaces.begin(), userWatchFaces.end(), [this](const WatchFaceDescription& watchfaceDescription) {
+ return watchfaceDescription.watchFace == settingsController.GetWatchFace();
+ });
+ if (watchFace != userWatchFaces.end())
+ currentScreen.reset(watchFace->create(controllers));
+ else {
+ currentScreen.reset(userWatchFaces[0].create(controllers));
+ }
+ settingsController.SetAppMenu(0);
+ } break;
case Apps::Error:
currentScreen = std::make_unique<Screens::Error>(bootError);
break;
@@ -409,14 +572,6 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
*systemTask,
Screens::Notifications::Modes::Preview);
break;
- case Apps::Timer:
- currentScreen = std::make_unique<Screens::Timer>(timerController);
- break;
- case Apps::Alarm:
- currentScreen = std::make_unique<Screens::Alarm>(alarmController, settingsController.GetClockType(), *systemTask, motorController);
- break;
-
- // Settings
case Apps::QuickSettings:
currentScreen = std::make_unique<Screens::QuickSettings>(this,
batteryController,
@@ -424,22 +579,32 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
brightnessController,
motorController,
settingsController,
- bleController);
+ bleController,
+ alarmController);
break;
case Apps::Settings:
currentScreen = std::make_unique<Screens::Settings>(this, settingsController);
break;
- case Apps::SettingWatchFace:
- currentScreen = std::make_unique<Screens::SettingWatchFace>(this, settingsController, filesystem);
- break;
+ case Apps::SettingWatchFace: {
+ std::array<Screens::SettingWatchFace::Item, UserWatchFaceTypes::Count> items;
+ int i = 0;
+ for (const auto& userWatchFace : userWatchFaces) {
+ items[i++] =
+ Screens::SettingWatchFace::Item {userWatchFace.name, userWatchFace.watchFace, userWatchFace.isAvailable(controllers.filesystem)};
+ }
+ currentScreen = std::make_unique<Screens::SettingWatchFace>(this, std::move(items), settingsController, filesystem);
+ } break;
case Apps::SettingTimeFormat:
currentScreen = std::make_unique<Screens::SettingTimeFormat>(settingsController);
break;
+ case Apps::SettingWeatherFormat:
+ currentScreen = std::make_unique<Screens::SettingWeatherFormat>(settingsController);
+ break;
case Apps::SettingWakeUp:
currentScreen = std::make_unique<Screens::SettingWakeUp>(settingsController);
break;
case Apps::SettingDisplay:
- currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
+ currentScreen = std::make_unique<Screens::SettingDisplay>(settingsController);
break;
case Apps::SettingSteps:
currentScreen = std::make_unique<Screens::SettingSteps>(settingsController);
@@ -467,38 +632,23 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
bleController,
watchdog,
motionController,
- touchPanel);
+ touchPanel,
+ spiNorFlash);
break;
case Apps::FlashLight:
currentScreen = std::make_unique<Screens::FlashLight>(*systemTask, brightnessController);
break;
- case Apps::StopWatch:
- currentScreen = std::make_unique<Screens::StopWatch>(*systemTask);
- break;
- case Apps::Twos:
- currentScreen = std::make_unique<Screens::Twos>();
- break;
- case Apps::Paint:
- currentScreen = std::make_unique<Screens::InfiniPaint>(lvgl, motorController);
- break;
- case Apps::Paddle:
- currentScreen = std::make_unique<Screens::Paddle>(lvgl);
- break;
- case Apps::Music:
- currentScreen = std::make_unique<Screens::Music>(systemTask->nimble().music());
- break;
- case Apps::Navigation:
- currentScreen = std::make_unique<Screens::Navigation>(systemTask->nimble().navigation());
- break;
- case Apps::HeartRate:
- currentScreen = std::make_unique<Screens::HeartRate>(heartRateController, *systemTask);
- break;
- case Apps::Metronome:
- currentScreen = std::make_unique<Screens::Metronome>(motorController, *systemTask);
- break;
- case Apps::Steps:
- currentScreen = std::make_unique<Screens::Steps>(motionController, settingsController);
+ default: {
+ const auto* d = std::find_if(userApps.begin(), userApps.end(), [app](const AppDescription& appDescription) {
+ return appDescription.app == app;
+ });
+ if (d != userApps.end()) {
+ currentScreen.reset(d->create(controllers));
+ } else {
+ currentScreen.reset(userWatchFaces[0].create(controllers));
+ }
break;
+ }
}
currentApp = app;
}
@@ -507,11 +657,17 @@ void DisplayApp::PushMessage(Messages msg) {
if (in_isr()) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken);
- if (xHigherPriorityTaskWoken == pdTRUE) {
- portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
- }
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
} else {
- xQueueSend(msgQueue, &msg, portMAX_DELAY);
+ TickType_t timeout = portMAX_DELAY;
+ // Make xQueueSend() non-blocking if the message is a Notification message. We do this to avoid
+ // deadlock between SystemTask and DisplayApp when their respective message queues are getting full
+ // when a lot of notifications are received on a very short time span.
+ if (msg == Messages::NewNotification) {
+ timeout = static_cast<TickType_t>(0);
+ }
+
+ xQueueSend(msgQueue, &msg, timeout);
}
}
@@ -548,6 +704,19 @@ void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) {
void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) {
this->systemTask = systemTask;
+ this->controllers.systemTask = systemTask;
+}
+
+void DisplayApp::Register(Pinetime::Controllers::SimpleWeatherService* weatherService) {
+ this->controllers.weatherController = weatherService;
+}
+
+void DisplayApp::Register(Pinetime::Controllers::MusicService* musicService) {
+ this->controllers.musicService = musicService;
+}
+
+void DisplayApp::Register(Pinetime::Controllers::NavigationService* NavigationService) {
+ this->controllers.navigationService = NavigationService;
}
void DisplayApp::ApplyBrightness() {
diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h
index 09111865..2f276eaf 100644
--- a/src/displayapp/DisplayApp.h
+++ b/src/displayapp/DisplayApp.h
@@ -4,7 +4,7 @@
#include <task.h>
#include <memory>
#include <systemtask/Messages.h>
-#include "displayapp/Apps.h"
+#include "displayapp/apps/Apps.h"
#include "displayapp/LittleVgl.h"
#include "displayapp/TouchEvents.h"
#include "components/brightness/BrightnessController.h"
@@ -12,14 +12,15 @@
#include "components/firmwarevalidator/FirmwareValidator.h"
#include "components/settings/Settings.h"
#include "displayapp/screens/Screen.h"
-#include "components/timer/TimerController.h"
+#include "components/timer/Timer.h"
#include "components/alarm/AlarmController.h"
#include "touchhandler/TouchHandler.h"
#include "displayapp/Messages.h"
#include "BootErrors.h"
-#include "StaticStack.h"
+#include "utility/StaticStack.h"
+#include "displayapp/Controllers.h"
namespace Pinetime {
@@ -38,6 +39,7 @@ namespace Pinetime {
class HeartRateController;
class MotionController;
class TouchHandler;
+ class SimpleWeatherService;
}
namespace System {
@@ -47,7 +49,7 @@ namespace Pinetime {
namespace Applications {
class DisplayApp {
public:
- enum class States { Idle, Running };
+ enum class States { Idle, Running, AOD };
enum class FullRefreshDirections { None, Up, Down, Left, Right, LeftAnim, RightAnim };
DisplayApp(Drivers::St7789& lcd,
@@ -61,11 +63,11 @@ namespace Pinetime {
Controllers::Settings& settingsController,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
- Pinetime::Controllers::TimerController& timerController,
Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::TouchHandler& touchHandler,
- Pinetime::Controllers::FS& filesystem);
+ Pinetime::Controllers::FS& filesystem,
+ Pinetime::Drivers::SpiNorFlash& spiNorFlash);
void Start(System::BootErrors error);
void PushMessage(Display::Messages msg);
@@ -74,6 +76,9 @@ namespace Pinetime {
void SetFullRefresh(FullRefreshDirections direction);
void Register(Pinetime::System::SystemTask* systemTask);
+ void Register(Pinetime::Controllers::SimpleWeatherService* weatherService);
+ void Register(Pinetime::Controllers::MusicService* musicService);
+ void Register(Pinetime::Controllers::NavigationService* NavigationService);
private:
Pinetime::Drivers::St7789& lcd;
@@ -88,15 +93,17 @@ namespace Pinetime {
Pinetime::Controllers::Settings& settingsController;
Pinetime::Controllers::MotorController& motorController;
Pinetime::Controllers::MotionController& motionController;
- Pinetime::Controllers::TimerController& timerController;
Pinetime::Controllers::AlarmController& alarmController;
Pinetime::Controllers::BrightnessController& brightnessController;
Pinetime::Controllers::TouchHandler& touchHandler;
Pinetime::Controllers::FS& filesystem;
+ Pinetime::Drivers::SpiNorFlash& spiNorFlash;
Pinetime::Controllers::FirmwareValidator validator;
Pinetime::Components::LittleVgl lvgl;
+ Pinetime::Controllers::Timer timer;
+ AppControllers controllers;
TaskHandle_t taskHandle;
States state = States::Running;
@@ -126,8 +133,17 @@ namespace Pinetime {
void ApplyBrightness();
static constexpr size_t returnAppStackSize = 10;
- StaticStack<Apps, returnAppStackSize> returnAppStack;
- StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections;
+ Utility::StaticStack<Apps, returnAppStackSize> returnAppStack;
+ Utility::StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections;
+
+ bool isDimmed = false;
+
+ TickType_t CalculateSleepTime();
+ TickType_t alwaysOnFrameCount;
+ TickType_t alwaysOnStartTime;
+ // If this is to be changed, make sure the actual always on refresh rate is changed
+ // by configuring the LCD refresh timings
+ static constexpr uint32_t alwaysOnRefreshPeriod = 500;
};
}
}
diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp
index 94e83791..bcb8db0e 100644
--- a/src/displayapp/DisplayAppRecovery.cpp
+++ b/src/displayapp/DisplayAppRecovery.cpp
@@ -21,11 +21,11 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
Controllers::Settings& /*settingsController*/,
Pinetime::Controllers::MotorController& /*motorController*/,
Pinetime::Controllers::MotionController& /*motionController*/,
- Pinetime::Controllers::TimerController& /*timerController*/,
Pinetime::Controllers::AlarmController& /*alarmController*/,
Pinetime::Controllers::BrightnessController& /*brightnessController*/,
Pinetime::Controllers::TouchHandler& /*touchHandler*/,
- Pinetime::Controllers::FS& /*filesystem*/)
+ Pinetime::Controllers::FS& /*filesystem*/,
+ Pinetime::Drivers::SpiNorFlash& /*spiNorFlash*/)
: lcd {lcd}, bleController {bleController} {
}
@@ -39,9 +39,6 @@ void DisplayApp::Process(void* instance) {
auto* app = static_cast<DisplayApp*>(instance);
NRF_LOG_INFO("displayapp task started!");
- // Send a dummy notification to unlock the lvgl display driver for the first iteration
- xTaskNotifyGive(xTaskGetCurrentTaskHandle());
-
app->InitHw();
while (true) {
app->Refresh();
@@ -95,7 +92,6 @@ void DisplayApp::DisplayLogo(uint16_t color) {
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
for (int i = 0; i < displayWidth; i++) {
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
- ulTaskNotifyTake(pdTRUE, 500);
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
}
}
@@ -104,21 +100,25 @@ void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
const uint8_t barHeight = 20;
std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
for (int i = 0; i < barHeight; i++) {
- ulTaskNotifyTake(pdTRUE, 500);
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
}
}
void DisplayApp::PushMessage(Display::Messages msg) {
- BaseType_t xHigherPriorityTaskWoken;
- xHigherPriorityTaskWoken = pdFALSE;
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken);
- if (xHigherPriorityTaskWoken) {
- /* Actual macro used here is port specific. */
- // TODO : should I do something here?
- }
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void DisplayApp::Register(Pinetime::System::SystemTask* /*systemTask*/) {
}
+
+void DisplayApp::Register(Pinetime::Controllers::SimpleWeatherService* /*weatherService*/) {
+}
+
+void DisplayApp::Register(Pinetime::Controllers::MusicService* /*musicService*/) {
+}
+
+void DisplayApp::Register(Pinetime::Controllers::NavigationService* /*NavigationService*/) {
+}
diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h
index 7be0c6d8..162ff257 100644
--- a/src/displayapp/DisplayAppRecovery.h
+++ b/src/displayapp/DisplayAppRecovery.h
@@ -5,13 +5,12 @@
#include <drivers/SpiMaster.h>
#include <bits/unique_ptr.h>
#include <queue.h>
-#include "components/gfx/Gfx.h"
#include "drivers/Cst816s.h"
#include <drivers/Watchdog.h>
#include <components/motor/MotorController.h>
#include "BootErrors.h"
#include "displayapp/TouchEvents.h"
-#include "displayapp/Apps.h"
+#include "displayapp/apps/Apps.h"
#include "displayapp/Messages.h"
namespace Pinetime {
@@ -19,6 +18,7 @@ namespace Pinetime {
class St7789;
class Cst816S;
class Watchdog;
+ class SpiNorFlash;
}
namespace Controllers {
@@ -31,10 +31,12 @@ namespace Pinetime {
class MotionController;
class TouchHandler;
class MotorController;
- class TimerController;
class AlarmController;
class BrightnessController;
class FS;
+ class SimpleWeatherService;
+ class MusicService;
+ class NavigationService;
}
namespace System {
@@ -55,11 +57,11 @@ namespace Pinetime {
Controllers::Settings& settingsController,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Controllers::MotionController& motionController,
- Pinetime::Controllers::TimerController& timerController,
Pinetime::Controllers::AlarmController& alarmController,
Pinetime::Controllers::BrightnessController& brightnessController,
Pinetime::Controllers::TouchHandler& touchHandler,
- Pinetime::Controllers::FS& filesystem);
+ Pinetime::Controllers::FS& filesystem,
+ Pinetime::Drivers::SpiNorFlash& spiNorFlash);
void Start();
void Start(Pinetime::System::BootErrors) {
@@ -68,6 +70,9 @@ namespace Pinetime {
void PushMessage(Pinetime::Applications::Display::Messages msg);
void Register(Pinetime::System::SystemTask* systemTask);
+ void Register(Pinetime::Controllers::SimpleWeatherService* weatherService);
+ void Register(Pinetime::Controllers::MusicService* musicService);
+ void Register(Pinetime::Controllers::NavigationService* NavigationService);
private:
TaskHandle_t taskHandle;
diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp
index 89893cf7..c6f6f784 100644
--- a/src/displayapp/LittleVgl.cpp
+++ b/src/displayapp/LittleVgl.cpp
@@ -152,10 +152,6 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
uint16_t y1, y2, width, height = 0;
- ulTaskNotifyTake(pdTRUE, 200);
- // Notification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
- // which cannot be set/clear during a transfer.
-
if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
} else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
@@ -219,7 +215,6 @@ void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
if (height > 0) {
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
- ulTaskNotifyTake(pdTRUE, 100);
}
uint16_t pixOffset = width * height;
@@ -253,6 +248,8 @@ void LittleVgl::SetNewTouchPoint(int16_t x, int16_t y, bool contact) {
}
}
+// Cancel an ongoing tap
+// Signifies that LVGL should not handle the current tap
void LittleVgl::CancelTap() {
if (tapped) {
isCancelled = true;
@@ -260,6 +257,13 @@ void LittleVgl::CancelTap() {
}
}
+// Clear the current tapped state
+// Signifies that touch input processing is suspended
+void LittleVgl::ClearTouchState() {
+ touchPoint = {-1, -1};
+ tapped = false;
+}
+
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
ptr->point.x = touchPoint.x;
ptr->point.y = touchPoint.y;
diff --git a/src/displayapp/LittleVgl.h b/src/displayapp/LittleVgl.h
index 9a15ae15..54505b36 100644
--- a/src/displayapp/LittleVgl.h
+++ b/src/displayapp/LittleVgl.h
@@ -26,6 +26,7 @@ namespace Pinetime {
void SetFullRefresh(FullRefreshDirections direction);
void SetNewTouchPoint(int16_t x, int16_t y, bool contact);
void CancelTap();
+ void ClearTouchState();
bool GetFullRefresh() {
bool returnValue = fullRefresh;
diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h
index b670b1aa..1fcd72d2 100644
--- a/src/displayapp/Messages.h
+++ b/src/displayapp/Messages.h
@@ -6,8 +6,8 @@ namespace Pinetime {
namespace Display {
enum class Messages : uint8_t {
GoToSleep,
+ GoToAOD,
GoToRunning,
- UpdateDateTime,
UpdateBleConnection,
TouchEvent,
ButtonPushed,
@@ -17,14 +17,13 @@ namespace Pinetime {
NewNotification,
TimerDone,
BleFirmwareUpdateStarted,
- UpdateTimeOut,
- DimScreen,
- RestoreBrightness,
+ // Resets the screen timeout timer when awake
+ // Does nothing when asleep
+ NotifyDeviceActivity,
ShowPairingKey,
AlarmTriggered,
Chime,
BleRadioEnableToggle,
- OnChargingEvent,
};
}
}
diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h
new file mode 100644
index 00000000..67bbfa7d
--- /dev/null
+++ b/src/displayapp/UserApps.h
@@ -0,0 +1,60 @@
+#pragma once
+#include "displayapp/apps/Apps.h"
+#include "Controllers.h"
+
+#include "displayapp/screens/Alarm.h"
+#include "displayapp/screens/Dice.h"
+#include "displayapp/screens/Timer.h"
+#include "displayapp/screens/Twos.h"
+#include "displayapp/screens/Tile.h"
+#include "displayapp/screens/ApplicationList.h"
+#include "displayapp/screens/WatchFaceDigital.h"
+#include "displayapp/screens/WatchFaceAnalog.h"
+#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
+#include "displayapp/screens/WatchFaceInfineat.h"
+#include "displayapp/screens/WatchFacePineTimeStyle.h"
+#include "displayapp/screens/WatchFaceTerminal.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Screen;
+ }
+
+ struct AppDescription {
+ Apps app;
+ const char* icon;
+ Screens::Screen* (*create)(AppControllers& controllers);
+ };
+
+ struct WatchFaceDescription {
+ WatchFace watchFace;
+ const char* name;
+ Screens::Screen* (*create)(AppControllers& controllers);
+ bool (*isAvailable)(Controllers::FS& fileSystem);
+ };
+
+ template <Apps t>
+ consteval AppDescription CreateAppDescription() {
+ return {AppTraits<t>::app, AppTraits<t>::icon, &AppTraits<t>::Create};
+ }
+
+ template <WatchFace t>
+ consteval WatchFaceDescription CreateWatchFaceDescription() {
+ return {WatchFaceTraits<t>::watchFace, WatchFaceTraits<t>::name, &WatchFaceTraits<t>::Create, &WatchFaceTraits<t>::IsAvailable};
+ }
+
+ template <template <Apps...> typename T, Apps... ts>
+ consteval std::array<AppDescription, sizeof...(ts)> CreateAppDescriptions(T<ts...>) {
+ return {CreateAppDescription<ts>()...};
+ }
+
+ template <template <WatchFace...> typename T, WatchFace... ts>
+ consteval std::array<WatchFaceDescription, sizeof...(ts)> CreateWatchFaceDescriptions(T<ts...>) {
+ return {CreateWatchFaceDescription<ts>()...};
+ }
+
+ constexpr auto userApps = CreateAppDescriptions(UserAppTypes {});
+ constexpr auto userWatchFaces = CreateWatchFaceDescriptions(UserWatchFaceTypes {});
+ }
+}
diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in
new file mode 100644
index 00000000..e697096a
--- /dev/null
+++ b/src/displayapp/apps/Apps.h.in
@@ -0,0 +1,80 @@
+#pragma once
+#include <cstddef>
+#include <cstdint>
+
+namespace Pinetime {
+ namespace Applications {
+ enum class Apps : uint8_t {
+ None,
+ Launcher,
+ Clock,
+ SysInfo,
+ FirmwareUpdate,
+ FirmwareValidation,
+ NotificationsPreview,
+ Notifications,
+ Timer,
+ Alarm,
+ FlashLight,
+ BatteryInfo,
+ Music,
+ Paint,
+ Paddle,
+ Twos,
+ HeartRate,
+ Navigation,
+ StopWatch,
+ Metronome,
+ Motion,
+ Calculator,
+ Steps,
+ Dice,
+ Weather,
+ PassKey,
+ QuickSettings,
+ Settings,
+ SettingWatchFace,
+ SettingTimeFormat,
+ SettingWeatherFormat,
+ SettingDisplay,
+ SettingWakeUp,
+ SettingSteps,
+ SettingSetDateTime,
+ SettingChimes,
+ SettingShakeThreshold,
+ SettingBluetooth,
+ Error
+ };
+
+ enum class WatchFace : uint8_t {
+ Digital,
+ Analog,
+ PineTimeStyle,
+ Terminal,
+ Infineat,
+ CasioStyleG7710,
+ };
+
+ template <Apps>
+ struct AppTraits {};
+
+ template <WatchFace>
+ struct WatchFaceTraits {};
+
+ template <Apps... As>
+ struct TypeList {
+ static constexpr size_t Count = sizeof...(As);
+ };
+
+ using UserAppTypes = TypeList<@USERAPP_TYPES@>;
+
+ template <WatchFace... Ws>
+ struct WatchFaceTypeList {
+ static constexpr size_t Count = sizeof...(Ws);
+ };
+
+ using UserWatchFaceTypes = WatchFaceTypeList<@WATCHFACE_TYPES@>;
+
+ static_assert(UserWatchFaceTypes::Count >= 1);
+ }
+}
diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt
new file mode 100644
index 00000000..33e54323
--- /dev/null
+++ b/src/displayapp/apps/CMakeLists.txt
@@ -0,0 +1,39 @@
+if(DEFINED ENABLE_USERAPPS)
+ set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware")
+else ()
+ set(DEFAULT_USER_APP_TYPES "Apps::StopWatch")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calculator")
+ set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
+ #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion")
+ set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")
+endif ()
+
+if(DEFINED ENABLE_WATCHFACES)
+ set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware")
+else()
+ set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital")
+ set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog")
+ set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle")
+ set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal")
+ set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat")
+ set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710")
+ set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware")
+endif()
+
+add_library(infinitime_apps INTERFACE)
+target_sources(infinitime_apps INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/Apps.h")
+target_include_directories(infinitime_apps INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/")
+
+# Generate the list of user apps to be compiled into the firmware
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Apps.h.in ${CMAKE_CURRENT_BINARY_DIR}/Apps.h)
diff --git a/src/displayapp/fonts/CMakeLists.txt b/src/displayapp/fonts/CMakeLists.txt
index 84830cc0..562f0801 100644
--- a/src/displayapp/fonts/CMakeLists.txt
+++ b/src/displayapp/fonts/CMakeLists.txt
@@ -1,6 +1,6 @@
set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20
- jetbrains_mono_extrabold_compressed lv_font_navi_80 lv_font_sys_48
- open_sans_light)
+ jetbrains_mono_extrabold_compressed lv_font_sys_48
+ open_sans_light fontawesome_weathericons)
find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
message(STATUS "Using ${LV_FONT_CONV} to generate font files")
@@ -11,6 +11,7 @@ configure_file(${CMAKE_CURRENT_LIST_DIR}/jetbrains_mono_bold_20.c_M.patch
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
# FindPython3 module introduces with CMake 3.12
# https://cmake.org/cmake/help/latest/module/FindPython3.html
+ set(Python3_FIND_STRATEGY LOCATION) # https://discourse.cmake.org/t/find-package-python3-is-not-finding-the-correct-python/10563
find_package(Python3 REQUIRED)
else()
set(Python3_EXECUTABLE "python")
diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md
index b2669a78..20fb4a43 100644
--- a/src/displayapp/fonts/README.md
+++ b/src/displayapp/fonts/README.md
@@ -16,7 +16,7 @@
- Define the new symbols in `src/displayapp/screens/Symbols.h`:
```
-static constexpr const char* newSymbol = "\xEF\x86\x85";
+static constexpr const char* newSymbol = "\xEF\x99\x81";
```
### the config file format:
@@ -33,3 +33,17 @@ and for each font there is:
### Navigation font
`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.
+
+To save space in the internal flash memory, the navigation icons are now moved into the external flash memory. To do this, the TTF font is converted into pictures (1 for each symbol). Those pictures are then concatenated into 2 big pictures (we need two files since LVGL supports maximum 2048px width/height). At runtime, a map is used to locate the desired icon in the corresponding file at a specific offset.
+
+Here is the command to convert the TTF font in PNG picture:
+
+```shell
+convert -background none -fill white -font navigation.ttf -pointsize 80 -gravity center label:"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" navigation0.png
+
+convert -background none -fill white -font navigation.ttf -pointsize 80 -gravity center label:"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" navigation1.png
+```
+
+*Please note that the characters after `label:` are UTF-8 characters and might not be displayed correctly in this document.*
+
+The characters in the TTF font range from `0xEEA480` to `0xEEA4A9`. Characters from `0xEEA480` to `0xEEA498` are stored in `navigation0.png` and the others in `navigation1.png`. Each character is 80px height so displaying a specific character consists in multiplying its index in the file by -80 and use this value as the offset when calling `lv_img_set_offset_y()`.
diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json
index 914ba163..fea31605 100644
--- a/src/displayapp/fonts/fonts.json
+++ b/src/displayapp/fonts/fonts.json
@@ -3,11 +3,11 @@
"sources": [
{
"file": "JetBrainsMono-Bold.ttf",
- "range": "0x20-0x7e, 0x410-0x44f"
+ "range": "0x20-0x7e, 0x410-0x44f, 0xB0"
},
{
"file": "FontAwesome5-Solid+Brands+Regular.woff",
- "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c"
+ "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a"
}
],
"bpp": 1,
@@ -18,7 +18,7 @@
"sources": [
{
"file": "JetBrainsMono-Regular.ttf",
- "range": "0x25, 0x2b, 0x2d, 0x30-0x3a"
+ "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x43, 0x46, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74, 0xb0"
}
],
"bpp": 1,
@@ -28,7 +28,7 @@
"sources": [
{
"file": "JetBrainsMono-Light.ttf",
- "range": "0x25, 0x2D, 0x2F, 0x30-0x3a"
+ "range": "0x25, 0x2D, 0x2F, 0x30-0x3a, 0x43, 0x46, 0xb0"
}
],
"bpp": 1,
@@ -64,15 +64,14 @@
"bpp": 1,
"size": 48
},
- "lv_font_navi_80": {
+ "fontawesome_weathericons": {
"sources": [
{
- "file": "navigation.ttf",
- "range": "0xe900-0xe929"
+ "file": "FontAwesome5-Solid+Brands+Regular.woff",
+ "range": "0xf185, 0xf6c4, 0xf743, 0xf740, 0xf75f, 0xf0c2, 0xf05e, 0xf73b, 0xf0e7, 0xf2dc"
}
],
- "bpp": 2,
- "size": 80,
- "compress": true
+ "bpp": 1,
+ "size": 25
}
}
diff --git a/src/displayapp/fonts/generate.py b/src/displayapp/fonts/generate.py
index 5f940bf5..88bdacd6 100755
--- a/src/displayapp/fonts/generate.py
+++ b/src/displayapp/fonts/generate.py
@@ -67,7 +67,7 @@ def main():
subprocess.check_call(line)
if patches:
for patch in patches:
- subprocess.check_call(['/usr/bin/env', 'patch', name+'.c', patch])
+ subprocess.check_call(['/usr/bin/env', 'patch', '--silent', name+'.c', patch])
diff --git a/src/displayapp/icons/bg_clock.c b/src/displayapp/icons/bg_clock.c
deleted file mode 100644
index a9de4146..00000000
--- a/src/displayapp/icons/bg_clock.c
+++ /dev/null
@@ -1,272 +0,0 @@
-#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
-#include "lvgl.h"
-#else
-#include "lvgl/lvgl.h"
-#endif
-
-
-#ifndef LV_ATTRIBUTE_MEM_ALIGN
-#define LV_ATTRIBUTE_MEM_ALIGN
-#endif
-
-#ifndef LV_ATTRIBUTE_IMG_BG_CLOCK
-#define LV_ATTRIBUTE_IMG_BG_CLOCK
-#endif
-
-const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BG_CLOCK uint8_t bg_clock_map[] = {
- 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/
- 0x68, 0x5b, 0x44, 0xff, /*Color of index 1*/
- 0xde, 0xa5, 0x33, 0xff, /*Color of index 2*/
- 0xff, 0xff, 0xff, 0xff, /*Color of index 3*/
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa4, 0x02, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa8, 0x0a, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xa8, 0x0a, 0x40, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x04, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xa8, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x06, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x0a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x06, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x1a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x1a, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x1a, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x55, 0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf4, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf4, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00,
- 0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x54, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x15, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x54, 0x00,
- 0x00, 0x01, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x55, 0x40,
- 0x00, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x55, 0x40,
- 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
- 0x00, 0x15, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x54, 0x00,
- 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00,
- 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x55, 0x00, 0x00,
- 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x55, 0x52, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xaa, 0xa8, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xaa, 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x06, 0x45, 0x01, 0x45, 0x40, 0x00, 0x54, 0x00, 0x60, 0x01, 0x40, 0x45, 0x50, 0x15, 0x00, 0x05, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x02, 0x46, 0x02, 0xaa, 0xa4, 0x06, 0x9a, 0x40, 0x60, 0x01, 0x80, 0xaa, 0xa9, 0xaa, 0x80, 0x1a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x02, 0x46, 0x02, 0x90, 0x28, 0x19, 0x01, 0x80, 0x60, 0x01, 0x80, 0xa0, 0x1a, 0x40, 0x90, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x0a, 0x06, 0x02, 0x80, 0x18, 0x18, 0x00, 0x90, 0x60, 0x01, 0x80, 0x90, 0x0a, 0x00, 0xa0, 0xa0, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xaa, 0xa9, 0x06, 0x02, 0x40, 0x18, 0x2a, 0xaa, 0x90, 0x60, 0x01, 0x80, 0x90, 0x09, 0x00, 0x60, 0xaa, 0xaa, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x95, 0x50, 0x06, 0x02, 0x40, 0x18, 0x28, 0x00, 0x00, 0x60, 0x01, 0x80, 0x90, 0x09, 0x00, 0x60, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x06, 0x02, 0x40, 0x18, 0x19, 0x00, 0x00, 0x60, 0x01, 0x80, 0x90, 0x09, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x06, 0x02, 0x40, 0x18, 0x0a, 0x56, 0x80, 0x60, 0x01, 0x80, 0x90, 0x09, 0x00, 0x60, 0x29, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x06, 0x02, 0x40, 0x18, 0x01, 0xa9, 0x00, 0x60, 0x01, 0x80, 0x90, 0x09, 0x00, 0x60, 0x06, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf4, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, 0x0a, 0xa0, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, 0x0a, 0xa0, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, 0x0a, 0xa0, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x00, 0x0a, 0xa0, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x0a, 0xa0, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-const lv_img_dsc_t bg_clock = {
- .header.always_zero = 0,
- .header.w = 240,
- .header.h = 240,
- .data_size = 14416,
- .header.cf = LV_IMG_CF_INDEXED_2BIT,
- .data = bg_clock_map,
-};
-
diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp
index 4e6ce797..4cf43921 100644
--- a/src/displayapp/screens/Alarm.cpp
+++ b/src/displayapp/screens/Alarm.cpp
@@ -19,6 +19,10 @@
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/InfiniTimeTheme.h"
+#include "components/settings/Settings.h"
+#include "components/alarm/AlarmController.h"
+#include "components/motor/MotorController.h"
+#include "systemtask/SystemTask.h"
using namespace Pinetime::Applications::Screens;
using Pinetime::Controllers::AlarmController;
@@ -44,7 +48,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
Controllers::Settings::ClockType clockType,
System::SystemTask& systemTask,
Controllers::MotorController& motorController)
- : alarmController {alarmController}, systemTask {systemTask}, motorController {motorController} {
+ : alarmController {alarmController}, wakeLock(systemTask), motorController {motorController} {
hourCounter.Create();
lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
@@ -73,7 +77,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
btnStop = lv_btn_create(lv_scr_act(), nullptr);
btnStop->user_data = this;
lv_obj_set_event_cb(btnStop, btnEventHandler);
- lv_obj_set_size(btnStop, 115, 50);
+ lv_obj_set_size(btnStop, 240, 70);
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);
@@ -113,7 +117,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
UpdateAlarmTime();
- if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) {
+ if (alarmController.IsAlerting()) {
SetAlerting();
} else {
SetSwitchState(LV_ANIM_OFF);
@@ -121,14 +125,15 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
}
Alarm::~Alarm() {
- if (alarmController.State() == AlarmController::AlarmState::Alerting) {
+ if (alarmController.IsAlerting()) {
StopAlerting();
}
lv_obj_clean(lv_scr_act());
+ alarmController.SaveAlarm();
}
void Alarm::DisableAlarm() {
- if (alarmController.State() == AlarmController::AlarmState::Set) {
+ if (alarmController.IsEnabled()) {
alarmController.DisableAlarm();
lv_switch_off(enableSwitch, LV_ANIM_ON);
}
@@ -168,7 +173,7 @@ bool Alarm::OnButtonPushed() {
HideInfo();
return true;
}
- if (alarmController.State() == AlarmController::AlarmState::Alerting) {
+ if (alarmController.IsAlerting()) {
StopAlerting();
return true;
}
@@ -177,7 +182,7 @@ bool Alarm::OnButtonPushed() {
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;
+ return alarmController.IsAlerting() && event == TouchEvents::SwipeDown;
}
void Alarm::OnValueChanged() {
@@ -198,10 +203,14 @@ void Alarm::UpdateAlarmTime() {
void Alarm::SetAlerting() {
lv_obj_set_hidden(enableSwitch, true);
+ lv_obj_set_hidden(btnRecur, true);
+ lv_obj_set_hidden(btnInfo, true);
+ hourCounter.HideControls();
+ minuteCounter.HideControls();
lv_obj_set_hidden(btnStop, false);
taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this);
motorController.StartRinging();
- systemTask.PushMessage(System::Messages::DisableSleeping);
+ wakeLock.Lock();
}
void Alarm::StopAlerting() {
@@ -212,21 +221,20 @@ void Alarm::StopAlerting() {
lv_task_del(taskStopAlarm);
taskStopAlarm = nullptr;
}
- systemTask.PushMessage(System::Messages::EnableSleeping);
- lv_obj_set_hidden(enableSwitch, false);
+ wakeLock.Release();
lv_obj_set_hidden(btnStop, true);
+ hourCounter.ShowControls();
+ minuteCounter.ShowControls();
+ lv_obj_set_hidden(btnInfo, false);
+ lv_obj_set_hidden(btnRecur, false);
+ lv_obj_set_hidden(enableSwitch, false);
}
void Alarm::SetSwitchState(lv_anim_enable_t anim) {
- switch (alarmController.State()) {
- case AlarmController::AlarmState::Set:
- lv_switch_on(enableSwitch, anim);
- break;
- case AlarmController::AlarmState::Not_Set:
- lv_switch_off(enableSwitch, anim);
- break;
- default:
- break;
+ if (alarmController.IsEnabled()) {
+ lv_switch_on(enableSwitch, anim);
+ } else {
+ lv_switch_off(enableSwitch, anim);
}
}
@@ -243,7 +251,7 @@ void Alarm::ShowInfo() {
txtMessage = lv_label_create(btnMessage, nullptr);
lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
- if (alarmController.State() == AlarmController::AlarmState::Set) {
+ if (alarmController.IsEnabled()) {
auto timeToAlarm = alarmController.SecondsToAlarm();
auto daysToAlarm = timeToAlarm / 86400;
diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h
index 91177366..a875b275 100644
--- a/src/displayapp/screens/Alarm.h
+++ b/src/displayapp/screens/Alarm.h
@@ -17,21 +17,23 @@
*/
#pragma once
+#include "displayapp/apps/Apps.h"
+#include "components/settings/Settings.h"
#include "displayapp/screens/Screen.h"
-#include "systemtask/SystemTask.h"
-#include "displayapp/LittleVgl.h"
-#include "components/alarm/AlarmController.h"
#include "displayapp/widgets/Counter.h"
+#include "displayapp/Controllers.h"
+#include "systemtask/WakeLock.h"
+#include "Symbols.h"
namespace Pinetime {
namespace Applications {
namespace Screens {
class Alarm : public Screen {
public:
- Alarm(Controllers::AlarmController& alarmController,
- Controllers::Settings::ClockType clockType,
- System::SystemTask& systemTask,
- Controllers::MotorController& motorController);
+ explicit Alarm(Controllers::AlarmController& alarmController,
+ Controllers::Settings::ClockType clockType,
+ System::SystemTask& systemTask,
+ Controllers::MotorController& motorController);
~Alarm() override;
void SetAlerting();
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
@@ -42,7 +44,7 @@ namespace Pinetime {
private:
Controllers::AlarmController& alarmController;
- System::SystemTask& systemTask;
+ System::WakeLock wakeLock;
Controllers::MotorController& motorController;
lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch;
@@ -63,6 +65,19 @@ namespace Pinetime {
Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76);
Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
};
+ }
+
+ template <>
+ struct AppTraits<Apps::Alarm> {
+ static constexpr Apps app = Apps::Alarm;
+ static constexpr const char* icon = Screens::Symbols::bell;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Alarm(controllers.alarmController,
+ controllers.settingsController.GetClockType(),
+ *controllers.systemTask,
+ controllers.motorController);
+ };
};
- };
+ }
}
diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp
index 0a65a5d4..fb46b413 100644
--- a/src/displayapp/screens/ApplicationList.cpp
+++ b/src/displayapp/screens/ApplicationList.cpp
@@ -1,13 +1,12 @@
#include "displayapp/screens/ApplicationList.h"
+#include "displayapp/screens/Tile.h"
#include <lvgl/lvgl.h>
#include <functional>
-#include "displayapp/Apps.h"
-#include "displayapp/DisplayApp.h"
+#include <algorithm>
+#include "components/settings/Settings.h"
using namespace Pinetime::Applications::Screens;
-constexpr std::array<Tile::Applications, ApplicationList::applications.size()> ApplicationList::applications;
-
auto ApplicationList::CreateScreenList() const {
std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens;
for (size_t i = 0; i < screens.size(); i++) {
@@ -18,16 +17,22 @@ auto ApplicationList::CreateScreenList() const {
return screens;
}
-ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
+ApplicationList::ApplicationList(DisplayApp* app,
Pinetime::Controllers::Settings& settingsController,
const Pinetime::Controllers::Battery& batteryController,
const Pinetime::Controllers::Ble& bleController,
- Controllers::DateTime& dateTimeController)
+ const Pinetime::Controllers::AlarmController& alarmController,
+ Controllers::DateTime& dateTimeController,
+ Pinetime::Controllers::FS& filesystem,
+ std::array<Tile::Applications, UserAppTypes::Count>&& apps)
: app {app},
settingsController {settingsController},
batteryController {batteryController},
bleController {bleController},
+ alarmController {alarmController},
dateTimeController {dateTimeController},
+ filesystem {filesystem},
+ apps {std::move(apps)},
screens {app, settingsController.GetAppMenu(), CreateScreenList(), Screens::ScreenListModes::UpDown} {
}
@@ -40,9 +45,14 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
std::unique_ptr<Screen> ApplicationList::CreateScreen(unsigned int screenNum) const {
- std::array<Tile::Applications, appsPerScreen> apps;
+ std::array<Tile::Applications, appsPerScreen> pageApps;
+
for (int i = 0; i < appsPerScreen; i++) {
- apps[i] = applications[screenNum * appsPerScreen + i];
+ if (i + (screenNum * appsPerScreen) >= apps.size()) {
+ pageApps[i] = {"", Pinetime::Applications::Apps::None, false};
+ } else {
+ pageApps[i] = apps[i + (screenNum * appsPerScreen)];
+ }
}
return std::make_unique<Screens::Tile>(screenNum,
@@ -51,6 +61,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen(unsigned int screenNum) co
settingsController,
batteryController,
bleController,
+ alarmController,
dateTimeController,
- apps);
+ pageApps);
}
diff --git a/src/displayapp/screens/ApplicationList.h b/src/displayapp/screens/ApplicationList.h
index 7bdd1154..4a57d7c0 100644
--- a/src/displayapp/screens/ApplicationList.h
+++ b/src/displayapp/screens/ApplicationList.h
@@ -2,14 +2,12 @@
#include <array>
#include <memory>
-
-#include "displayapp/screens/Screen.h"
-#include "displayapp/screens/ScreenList.h"
-#include "components/datetime/DateTimeController.h"
-#include "components/settings/Settings.h"
-#include "components/battery/BatteryController.h"
-#include "displayapp/screens/Symbols.h"
-#include "displayapp/screens/Tile.h"
+#include "displayapp/apps/Apps.h"
+#include "Screen.h"
+#include "ScreenList.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
+#include "Tile.h"
namespace Pinetime {
namespace Applications {
@@ -20,7 +18,10 @@ namespace Pinetime {
Pinetime::Controllers::Settings& settingsController,
const Pinetime::Controllers::Battery& batteryController,
const Pinetime::Controllers::Ble& bleController,
- Controllers::DateTime& dateTimeController);
+ const Pinetime::Controllers::AlarmController& alarmController,
+ Controllers::DateTime& dateTimeController,
+ Pinetime::Controllers::FS& filesystem,
+ std::array<Tile::Applications, UserAppTypes::Count>&& apps);
~ApplicationList() override;
bool OnTouchEvent(TouchEvents event) override;
@@ -32,30 +33,15 @@ namespace Pinetime {
Controllers::Settings& settingsController;
const Pinetime::Controllers::Battery& batteryController;
const Pinetime::Controllers::Ble& bleController;
+ const Pinetime::Controllers::AlarmController& alarmController;
Controllers::DateTime& dateTimeController;
+ Pinetime::Controllers::FS& filesystem;
+ std::array<Tile::Applications, UserAppTypes::Count> apps;
static constexpr int appsPerScreen = 6;
- // Increment this when more space is needed
- static constexpr int nScreens = 2;
-
- static constexpr std::array<Tile::Applications, appsPerScreen * nScreens> applications {{
- {Symbols::stopWatch, Apps::StopWatch},
- {Symbols::clock, Apps::Alarm},
- {Symbols::hourGlass, Apps::Timer},
- {Symbols::shoe, Apps::Steps},
- {Symbols::heartBeat, Apps::HeartRate},
- {Symbols::music, Apps::Music},
-
- {Symbols::paintbrush, Apps::Paint},
- {Symbols::paddle, Apps::Paddle},
- {"2", Apps::Twos},
- {Symbols::drum, Apps::Metronome},
- {Symbols::map, Apps::Navigation},
- {Symbols::none, Apps::None},
+ static constexpr int nScreens = UserAppTypes::Count > 0 ? (UserAppTypes::Count - 1) / appsPerScreen + 1 : 1;
- // {"M", Apps::Motion},
- }};
ScreenList<nScreens> screens;
};
}
diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp
index ab0a2bd4..20401988 100644
--- a/src/displayapp/screens/BatteryInfo.cpp
+++ b/src/displayapp/screens/BatteryInfo.cpp
@@ -10,33 +10,35 @@ BatteryInfo::BatteryInfo(const Pinetime::Controllers::Battery& batteryController
batteryPercent = batteryController.PercentRemaining();
batteryVoltage = batteryController.Voltage();
- charging_bar = lv_bar_create(lv_scr_act(), nullptr);
- lv_obj_set_size(charging_bar, 200, 15);
- lv_bar_set_range(charging_bar, 0, 100);
- lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
- lv_bar_set_anim_time(charging_bar, 1000);
- lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
- lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt);
- lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
- lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
- lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
+ chargingArc = lv_arc_create(lv_scr_act(), nullptr);
+ lv_arc_set_rotation(chargingArc, 270);
+ lv_arc_set_bg_angles(chargingArc, 0, 360);
+ lv_arc_set_adjustable(chargingArc, false);
+ lv_obj_set_size(chargingArc, 180, 180);
+ lv_obj_align(chargingArc, nullptr, LV_ALIGN_CENTER, 0, -30);
+ lv_arc_set_value(chargingArc, batteryPercent);
+ lv_obj_set_style_local_bg_opa(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
+ lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt);
+ lv_obj_set_style_local_border_width(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2);
+ lv_obj_set_style_local_radius(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
+ lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_LIME);
status = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(status, "Reading Battery status");
lv_label_set_align(status, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
+ lv_obj_align(status, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -17);
percent = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
+ lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT);
- lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
+ lv_obj_align(percent, chargingArc, LV_ALIGN_CENTER, 0, 0);
voltage = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
+ lv_obj_align(voltage, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -7);
taskRefresh = lv_task_create(RefreshTaskCallback, 5000, LV_TASK_PRIO_MID, this);
Refresh();
@@ -53,22 +55,23 @@ void BatteryInfo::Refresh() {
batteryVoltage = batteryController.Voltage();
if (batteryController.IsCharging()) {
- lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
+ lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_LIME);
lv_label_set_text_static(status, "Charging");
} else if (batteryPercent == 100) {
- lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
+ lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_label_set_text_static(status, "Fully charged");
} else if (batteryPercent < 10) {
- lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
+ lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text_static(status, "Battery low");
} else {
- lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::highlight);
+ lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_label_set_text_static(status, "Discharging");
}
lv_label_set_text_fmt(percent, "%02i%%", batteryPercent);
+ lv_obj_align(percent, chargingArc, LV_ALIGN_CENTER, 0, 0);
- lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
+ lv_obj_align(status, voltage, LV_ALIGN_IN_BOTTOM_MID, 0, -27);
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
- lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
+ lv_arc_set_value(chargingArc, batteryPercent);
}
diff --git a/src/displayapp/screens/BatteryInfo.h b/src/displayapp/screens/BatteryInfo.h
index aa01d464..27bbaa00 100644
--- a/src/displayapp/screens/BatteryInfo.h
+++ b/src/displayapp/screens/BatteryInfo.h
@@ -24,7 +24,7 @@ namespace Pinetime {
lv_obj_t* voltage;
lv_obj_t* percent;
- lv_obj_t* charging_bar;
+ lv_obj_t* chargingArc;
lv_obj_t* status;
lv_task_t* taskRefresh;
diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp
new file mode 100644
index 00000000..a1f09383
--- /dev/null
+++ b/src/displayapp/screens/Calculator.cpp
@@ -0,0 +1,375 @@
+#include <cmath>
+#include <cinttypes>
+#include "Calculator.h"
+#include "displayapp/InfiniTimeTheme.h"
+#include "Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+static void eventHandler(lv_obj_t* obj, lv_event_t event) {
+ auto app = static_cast<Calculator*>(obj->user_data);
+ app->OnButtonEvent(obj, event);
+}
+
+Calculator::~Calculator() {
+ lv_obj_clean(lv_scr_act());
+}
+
+constexpr const char* const buttonMap[] = {
+ "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""};
+
+Calculator::Calculator() {
+ resultLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP);
+ lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT);
+ lv_label_set_text_fmt(resultLabel, "%" PRId64, result);
+ lv_obj_set_size(resultLabel, 200, 20);
+ lv_obj_set_pos(resultLabel, 10, 5);
+
+ valueLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP);
+ lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT);
+ lv_label_set_text_fmt(valueLabel, "%" PRId64, value);
+ lv_obj_set_size(valueLabel, 200, 20);
+ lv_obj_set_pos(valueLabel, 10, 35);
+
+ buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr);
+ buttonMatrix->user_data = this;
+ lv_obj_set_event_cb(buttonMatrix, eventHandler);
+ lv_btnmatrix_set_map(buttonMatrix, const_cast<const char**>(buttonMap));
+ lv_btnmatrix_set_one_check(buttonMatrix, true);
+ lv_obj_set_size(buttonMatrix, 238, 180);
+ lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::bgAlt);
+ lv_obj_set_style_local_pad_inner(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1);
+ lv_obj_set_style_local_pad_top(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1);
+ lv_obj_set_style_local_pad_bottom(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1);
+ lv_obj_set_style_local_pad_left(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1);
+ lv_obj_set_style_local_pad_right(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1);
+ lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+
+ lv_obj_set_style_local_bg_opa(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_OPA_COVER);
+ lv_obj_set_style_local_bg_grad_stop(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, 128);
+ lv_obj_set_style_local_bg_main_stop(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, 128);
+}
+
+void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
+ if ((obj == buttonMatrix) && (event == LV_EVENT_PRESSED)) {
+ HandleInput();
+ }
+}
+
+void Calculator::HandleInput() {
+ const char* buttonText = lv_btnmatrix_get_active_btn_text(buttonMatrix);
+
+ if (buttonText == nullptr) {
+ return;
+ }
+
+ if ((equalSignPressedBefore && (*buttonText != '=')) || (error != Error::None)) {
+ ResetInput();
+ UpdateOperation();
+ }
+
+ // we only compare the first char because it is enough
+ switch (*buttonText) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ // *buttonText is the first char in buttonText
+ // "- '0'" results in the int value of the char
+ uint8_t digit = (*buttonText) - '0';
+ int8_t sign = (value < 0) ? -1 : 1;
+
+ // if this is true, we already pressed the . button
+ if (offset < FIXED_POINT_OFFSET) {
+ value += sign * offset * digit;
+ offset /= 10;
+ } else if (value <= MAX_VALUE / 10) {
+ value *= 10;
+ value += sign * offset * digit;
+ }
+ } break;
+
+ // unary minus
+ case '(':
+ value = -value;
+ break;
+
+ case '.':
+ if (offset == FIXED_POINT_OFFSET) {
+ offset /= 10;
+ }
+ break;
+
+ // for every operator we:
+ // - eval the current operator if value > FIXED_POINT_OFFSET
+ // - then set the new operator
+ // - + and - as well as * and / cycle on the same button
+ case '+':
+ if (value != 0) {
+ Eval();
+ ResetInput();
+ }
+
+ switch (operation) {
+ case '+':
+ operation = '-';
+ break;
+ case '-':
+ operation = ' ';
+ break;
+ default:
+ operation = '+';
+ break;
+ }
+ UpdateOperation();
+ break;
+
+ case '*':
+ if (value != 0) {
+ Eval();
+ ResetInput();
+ }
+
+ switch (operation) {
+ case '*':
+ operation = '/';
+ break;
+ case '/':
+ operation = ' ';
+ break;
+ default:
+ operation = '*';
+ break;
+ }
+ UpdateOperation();
+ break;
+
+ // this is a little hacky because it matches only the first char
+ case Symbols::backspace[0]:
+ if (value != 0) {
+ // delete one value digit
+ if (offset < FIXED_POINT_OFFSET) {
+ if (offset == 0) {
+ offset = 1;
+ } else {
+ offset *= 10;
+ }
+ } else {
+ value /= 10;
+ }
+ if (offset < FIXED_POINT_OFFSET) {
+ value -= value % (10 * offset);
+ } else {
+ value -= value % offset;
+ }
+ } else if (offset < FIXED_POINT_OFFSET) {
+ if (offset == 0) {
+ offset = 1;
+ } else {
+ offset *= 10;
+ }
+ } else {
+ // reset the result
+ result = 0;
+ }
+
+ if (value == 0) {
+ operation = ' ';
+ UpdateOperation();
+ }
+ break;
+
+ case '=':
+ equalSignPressedBefore = true;
+ Eval();
+ // If the operation is ' ' then we move the value to the result.
+ // We reset the input after this.
+ // This seems more convenient.
+ if (operation == ' ') {
+ ResetInput();
+ }
+ break;
+ }
+
+ UpdateValueLabel();
+ UpdateResultLabel();
+}
+
+void Calculator::UpdateOperation() const {
+ switch (operation) {
+ case '+':
+ lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR);
+ lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange);
+ lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt);
+ lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE);
+ break;
+ case '-':
+ lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR);
+ lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt);
+ lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange);
+ lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE);
+ break;
+ case '*':
+ lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR);
+ lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange);
+ lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt);
+ lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE);
+ break;
+ case '/':
+ lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR);
+ lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt);
+ lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange);
+ lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE);
+ break;
+ default:
+ lv_btnmatrix_clear_btn_ctrl_all(buttonMatrix, LV_BTNMATRIX_CTRL_CHECK_STATE);
+ break;
+ }
+}
+
+void Calculator::ResetInput() {
+ value = 0;
+ offset = FIXED_POINT_OFFSET;
+ operation = ' ';
+ equalSignPressedBefore = false;
+ error = Error::None;
+}
+
+void Calculator::UpdateResultLabel() const {
+ int64_t integer = result / FIXED_POINT_OFFSET;
+ int64_t remainder = result % FIXED_POINT_OFFSET;
+ bool negative = (remainder < 0);
+
+ if (remainder == 0) {
+ lv_label_set_text_fmt(resultLabel, "%" PRId64, integer);
+ return;
+ }
+
+ if (remainder < 0) {
+ remainder = -remainder;
+ }
+
+ uint8_t minWidth = N_DECIMALS;
+
+ // cut "0"-digits on the right
+ while ((remainder > 0) && (remainder % 10 == 0)) {
+ remainder /= 10;
+ minWidth--;
+ }
+
+ if ((integer == 0) && negative) {
+ lv_label_set_text_fmt(resultLabel, "-0.%0*" PRId64, minWidth, remainder);
+ } else {
+ lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*" PRId64, integer, minWidth, remainder);
+ }
+}
+
+void Calculator::UpdateValueLabel() {
+ switch (error) {
+ case Error::TooLarge:
+ lv_label_set_text_static(valueLabel, "too large");
+ break;
+ case Error::ZeroDivision:
+ lv_label_set_text_static(valueLabel, "zero division");
+ break;
+ case Error::None:
+ default: {
+ int64_t integer = value / FIXED_POINT_OFFSET;
+ int64_t remainder = value % FIXED_POINT_OFFSET;
+ bool negative = (remainder < 0);
+
+ int64_t printRemainder = remainder < 0 ? -remainder : remainder;
+
+ uint8_t minWidth = 0;
+ int64_t tmpOffset = offset;
+
+ if (tmpOffset == 0) {
+ tmpOffset = 1;
+ minWidth = 1;
+ }
+ while (tmpOffset < FIXED_POINT_OFFSET) {
+ tmpOffset *= 10;
+ minWidth++;
+ }
+ minWidth--;
+
+ for (uint8_t i = minWidth; i < N_DECIMALS; i++) {
+ printRemainder /= 10;
+ }
+
+ if ((integer == 0) && negative) {
+ lv_label_set_text_fmt(valueLabel, "-0.%0*" PRId64, minWidth, printRemainder);
+ } else if (offset == FIXED_POINT_OFFSET) {
+ lv_label_set_text_fmt(valueLabel, "%" PRId64, integer);
+ } else if ((offset == (FIXED_POINT_OFFSET / 10)) && (remainder == 0)) {
+ lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer);
+ } else {
+ lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, minWidth, printRemainder);
+ }
+ } break;
+ }
+}
+
+// update the result based on value and operation
+void Calculator::Eval() {
+ switch (operation) {
+ case ' ':
+ result = value;
+ break;
+
+ case '+':
+ // check for overflow
+ if (((result > 0) && (value > (MAX_VALUE - result))) || ((result < 0) && (value < (MIN_VALUE - result)))) {
+ error = Error::TooLarge;
+ break;
+ }
+
+ result += value;
+ break;
+ case '-':
+ // check for overflow
+ if (((result < 0) && (value > (MAX_VALUE + result))) || ((result > 0) && (value < (MIN_VALUE + result)))) {
+ error = Error::TooLarge;
+ break;
+ }
+
+ result -= value;
+ break;
+ case '*':
+ // check for overflow
+ // while dividing we eliminate the fixed point offset
+ // therefore we have to multiply it again for the comparison with value
+ // we also assume here that MAX_VALUE == -MIN_VALUE
+ if ((result != 0) && (std::abs(value) > (FIXED_POINT_OFFSET * (MAX_VALUE / std::abs(result))))) {
+ error = Error::TooLarge;
+ break;
+ }
+
+ result *= value;
+ // fixed point offset was multiplied too
+ result /= FIXED_POINT_OFFSET;
+ break;
+ case '/':
+ // check for zero division
+ if (value == 0) {
+ error = Error::ZeroDivision;
+ break;
+ }
+
+ // fixed point offset will be divided too
+ result *= FIXED_POINT_OFFSET;
+ result /= value;
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h
new file mode 100644
index 00000000..9971f275
--- /dev/null
+++ b/src/displayapp/screens/Calculator.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "displayapp/screens/Screen.h"
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
+
+namespace {
+ constexpr int64_t powi(int64_t base, uint8_t exponent) {
+ int64_t value = 1;
+ while (exponent) {
+ value *= base;
+ exponent--;
+ }
+ return value;
+ }
+}
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Calculator : public Screen {
+ public:
+ ~Calculator() override;
+
+ Calculator();
+
+ void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
+
+ private:
+ lv_obj_t* buttonMatrix {};
+ lv_obj_t* valueLabel {};
+ lv_obj_t* resultLabel {};
+
+ void Eval();
+ void ResetInput();
+ void HandleInput();
+ void UpdateValueLabel();
+ void UpdateResultLabel() const;
+ void UpdateOperation() const;
+
+ // change this if you want to change the number of decimals
+ // keep in mind, that we only have 12 digits in total (see MAX_DIGITS)
+ // due to the fixed point implementation
+ static constexpr uint8_t N_DECIMALS = 3;
+ // this is the constant default offset
+ static constexpr int64_t FIXED_POINT_OFFSET = powi(10, N_DECIMALS);
+ // this is the current offset, may vary after pressing '.'
+ int64_t offset = FIXED_POINT_OFFSET;
+
+ // the screen can show 12 chars
+ // but two are needed for '.' and '-'
+ static constexpr uint8_t MAX_DIGITS = 12;
+ static constexpr int64_t MAX_VALUE = powi(10, MAX_DIGITS) - 1;
+ // this is assumed in the multiplication overflow!
+ static constexpr int64_t MIN_VALUE = -MAX_VALUE;
+
+ int64_t value = 0;
+ int64_t result = 0;
+ char operation = ' ';
+ bool equalSignPressedBefore = false;
+
+ enum Error {
+ TooLarge,
+ ZeroDivision,
+ None,
+ };
+
+ Error error = Error::None;
+ };
+ }
+
+ template <>
+ struct AppTraits<Apps::Calculator> {
+ static constexpr Apps app = Apps::Calculator;
+ static constexpr const char* icon = Screens::Symbols::calculator;
+
+ static Screens::Screen* Create(AppControllers& /* controllers */) {
+ return new Screens::Calculator();
+ };
+ };
+ }
+}
diff --git a/src/displayapp/screens/CheckboxList.h b/src/displayapp/screens/CheckboxList.h
index c208bc48..c6119970 100644
--- a/src/displayapp/screens/CheckboxList.h
+++ b/src/displayapp/screens/CheckboxList.h
@@ -1,6 +1,6 @@
#pragma once
-#include "displayapp/Apps.h"
+#include "displayapp/apps/Apps.h"
#include "displayapp/screens/Screen.h"
#include <array>
#include <cstdint>
diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp
deleted file mode 100644
index a03dc68b..00000000
--- a/src/displayapp/screens/Clock.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "displayapp/screens/Clock.h"
-
-#include <lvgl/lvgl.h>
-#include "components/battery/BatteryController.h"
-#include "components/motion/MotionController.h"
-#include "components/ble/BleController.h"
-#include "components/ble/NotificationManager.h"
-#include "components/settings/Settings.h"
-#include "displayapp/DisplayApp.h"
-#include "displayapp/screens/WatchFaceDigital.h"
-#include "displayapp/screens/WatchFaceTerminal.h"
-#include "displayapp/screens/WatchFaceInfineat.h"
-#include "displayapp/screens/WatchFaceAnalog.h"
-#include "displayapp/screens/WatchFacePineTimeStyle.h"
-#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
-
-using namespace Pinetime::Applications::Screens;
-
-Clock::Clock(Controllers::DateTime& dateTimeController,
- const Controllers::Battery& batteryController,
- const Controllers::Ble& bleController,
- Controllers::NotificationManager& notificationManager,
- Controllers::Settings& settingsController,
- Controllers::HeartRateController& heartRateController,
- Controllers::MotionController& motionController,
- Controllers::FS& filesystem)
- : dateTimeController {dateTimeController},
- batteryController {batteryController},
- bleController {bleController},
- notificationManager {notificationManager},
- settingsController {settingsController},
- heartRateController {heartRateController},
- motionController {motionController},
- filesystem {filesystem},
- screen {[this, &settingsController]() {
- switch (settingsController.GetClockFace()) {
- case 0:
- return WatchFaceDigitalScreen();
- break;
- case 1:
- return WatchFaceAnalogScreen();
- break;
- case 2:
- return WatchFacePineTimeStyleScreen();
- break;
- case 3:
- return WatchFaceTerminalScreen();
- break;
- case 4:
- return WatchFaceInfineatScreen();
- break;
- case 5:
- return WatchFaceCasioStyleG7710();
- break;
- }
- return WatchFaceDigitalScreen();
- }()} {
- settingsController.SetAppMenu(0);
-}
-
-Clock::~Clock() {
- lv_obj_clean(lv_scr_act());
-}
-
-bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
- return screen->OnTouchEvent(event);
-}
-
-bool Clock::OnButtonPushed() {
- return screen->OnButtonPushed();
-}
-
-std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
- return std::make_unique<Screens::WatchFaceDigital>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController,
- heartRateController,
- motionController);
-}
-
-std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
- return std::make_unique<Screens::WatchFaceAnalog>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController);
-}
-
-std::unique_ptr<Screen> Clock::WatchFacePineTimeStyleScreen() {
- return std::make_unique<Screens::WatchFacePineTimeStyle>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController,
- motionController);
-}
-
-std::unique_ptr<Screen> Clock::WatchFaceTerminalScreen() {
- return std::make_unique<Screens::WatchFaceTerminal>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController,
- heartRateController,
- motionController);
-}
-
-std::unique_ptr<Screen> Clock::WatchFaceInfineatScreen() {
- return std::make_unique<Screens::WatchFaceInfineat>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController,
- motionController,
- filesystem);
-}
-
-std::unique_ptr<Screen> Clock::WatchFaceCasioStyleG7710() {
- return std::make_unique<Screens::WatchFaceCasioStyleG7710>(dateTimeController,
- batteryController,
- bleController,
- notificationManager,
- settingsController,
- heartRateController,
- motionController,
- filesystem);
-}
diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h
deleted file mode 100644
index 8c987fbb..00000000
--- a/src/displayapp/screens/Clock.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#pragma once
-
-#include <lvgl/src/lv_core/lv_obj.h>
-#include <chrono>
-#include <cstdint>
-#include <memory>
-#include <components/heartrate/HeartRateController.h>
-#include "displayapp/screens/Screen.h"
-#include "components/datetime/DateTimeController.h"
-
-namespace Pinetime {
- namespace Controllers {
- class Settings;
- class Battery;
- class Ble;
- class NotificationManager;
- class MotionController;
- }
-
- namespace Applications {
- namespace Screens {
- class Clock : public Screen {
- public:
- Clock(Controllers::DateTime& dateTimeController,
- const Controllers::Battery& batteryController,
- const Controllers::Ble& bleController,
- Controllers::NotificationManager& notificationManager,
- Controllers::Settings& settingsController,
- Controllers::HeartRateController& heartRateController,
- Controllers::MotionController& motionController,
- Controllers::FS& filesystem);
- ~Clock() override;
-
- bool OnTouchEvent(TouchEvents event) override;
- bool OnButtonPushed() override;
-
- private:
- Controllers::DateTime& dateTimeController;
- const Controllers::Battery& batteryController;
- const Controllers::Ble& bleController;
- Controllers::NotificationManager& notificationManager;
- Controllers::Settings& settingsController;
- Controllers::HeartRateController& heartRateController;
- Controllers::MotionController& motionController;
- Controllers::FS& filesystem;
-
- std::unique_ptr<Screen> screen;
- std::unique_ptr<Screen> WatchFaceDigitalScreen();
- std::unique_ptr<Screen> WatchFaceAnalogScreen();
- std::unique_ptr<Screen> WatchFacePineTimeStyleScreen();
- std::unique_ptr<Screen> WatchFaceTerminalScreen();
- std::unique_ptr<Screen> WatchFaceInfineatScreen();
- std::unique_ptr<Screen> WatchFaceCasioStyleG7710();
- };
- }
- }
-}
diff --git a/src/displayapp/screens/Dice.cpp b/src/displayapp/screens/Dice.cpp
new file mode 100644
index 00000000..302c5f3f
--- /dev/null
+++ b/src/displayapp/screens/Dice.cpp
@@ -0,0 +1,199 @@
+#include "displayapp/screens/Dice.h"
+#include "displayapp/screens/Screen.h"
+#include "displayapp/screens/Symbols.h"
+#include "components/settings/Settings.h"
+#include "components/motor/MotorController.h"
+#include "components/motion/MotionController.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ lv_obj_t* MakeLabel(lv_font_t* font,
+ lv_color_t color,
+ lv_label_long_mode_t longMode,
+ uint8_t width,
+ lv_label_align_t labelAlignment,
+ const char* text,
+ lv_obj_t* reference,
+ lv_align_t alignment,
+ int8_t x,
+ int8_t y) {
+ lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
+ lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color);
+ lv_label_set_long_mode(label, longMode);
+ if (width != 0) {
+ lv_obj_set_width(label, width);
+ }
+ lv_label_set_align(label, labelAlignment);
+ lv_label_set_text(label, text);
+ lv_obj_align(label, reference, alignment, x, y);
+ return label;
+ }
+
+ void btnRollEventHandler(lv_obj_t* obj, lv_event_t event) {
+ auto* screen = static_cast<Dice*>(obj->user_data);
+ if (event == LV_EVENT_CLICKED) {
+ screen->Roll();
+ }
+ }
+}
+
+Dice::Dice(Controllers::MotionController& motionController,
+ Controllers::MotorController& motorController,
+ Controllers::Settings& settingsController)
+ : motorController {motorController}, motionController {motionController}, settingsController {settingsController} {
+ std::seed_seq sseq {static_cast<uint32_t>(xTaskGetTickCount()),
+ static_cast<uint32_t>(motionController.X()),
+ static_cast<uint32_t>(motionController.Y()),
+ static_cast<uint32_t>(motionController.Z())};
+ gen.seed(sseq);
+
+ lv_obj_t* nCounterLabel = MakeLabel(&jetbrains_mono_bold_20,
+ LV_COLOR_WHITE,
+ LV_LABEL_LONG_EXPAND,
+ 0,
+ LV_LABEL_ALIGN_CENTER,
+ "count",
+ lv_scr_act(),
+ LV_ALIGN_IN_TOP_LEFT,
+ 0,
+ 0);
+
+ lv_obj_t* dCounterLabel = MakeLabel(&jetbrains_mono_bold_20,
+ LV_COLOR_WHITE,
+ LV_LABEL_LONG_EXPAND,
+ 0,
+ LV_LABEL_ALIGN_CENTER,
+ "sides",
+ nCounterLabel,
+ LV_ALIGN_OUT_RIGHT_MID,
+ 20,
+ 0);
+
+ nCounter.Create();
+ lv_obj_align(nCounter.GetObject(), nCounterLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
+ nCounter.SetValue(1);
+
+ dCounter.Create();
+ lv_obj_align(dCounter.GetObject(), dCounterLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
+ dCounter.SetValue(6);
+
+ std::uniform_int_distribution<> distrib(0, resultColors.size() - 1);
+ currentColorIndex = distrib(gen);
+
+ resultTotalLabel = MakeLabel(&jetbrains_mono_42,
+ resultColors[currentColorIndex],
+ LV_LABEL_LONG_BREAK,
+ 120,
+ LV_LABEL_ALIGN_CENTER,
+ "",
+ lv_scr_act(),
+ LV_ALIGN_IN_TOP_RIGHT,
+ 11,
+ 38);
+ resultIndividualLabel = MakeLabel(&jetbrains_mono_bold_20,
+ resultColors[currentColorIndex],
+ LV_LABEL_LONG_BREAK,
+ 90,
+ LV_LABEL_ALIGN_CENTER,
+ "",
+ resultTotalLabel,
+ LV_ALIGN_OUT_BOTTOM_MID,
+ 0,
+ 10);
+
+ Roll();
+ openingRoll = false;
+
+ btnRoll = lv_btn_create(lv_scr_act(), nullptr);
+ btnRoll->user_data = this;
+ lv_obj_set_event_cb(btnRoll, btnRollEventHandler);
+ lv_obj_set_size(btnRoll, 240, 50);
+ lv_obj_align(btnRoll, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+
+ btnRollLabel = MakeLabel(&jetbrains_mono_bold_20,
+ LV_COLOR_WHITE,
+ LV_LABEL_LONG_EXPAND,
+ 0,
+ LV_LABEL_ALIGN_CENTER,
+ Symbols::dice,
+ btnRoll,
+ LV_ALIGN_CENTER,
+ 0,
+ 0);
+
+ // Spagetti code in motion controller: it only updates the shake speed when shake to wake is on...
+ enableShakeForDice = !settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake);
+ if (enableShakeForDice) {
+ settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::Shake, true);
+ }
+ refreshTask = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
+}
+
+Dice::~Dice() {
+ // reset the shake to wake mode.
+ if (enableShakeForDice) {
+ settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::Shake, false);
+ enableShakeForDice = false;
+ }
+ lv_task_del(refreshTask);
+ lv_obj_clean(lv_scr_act());
+}
+
+void Dice::Refresh() {
+ // we only reset the hysteresis when at rest
+ if (motionController.CurrentShakeSpeed() >= settingsController.GetShakeThreshold()) {
+ if (currentRollHysteresis <= 0) {
+ // this timestamp is used for the screen timeout
+ lv_disp_get_next(NULL)->last_activity_time = lv_tick_get();
+
+ Roll();
+ }
+ } else if (currentRollHysteresis > 0)
+ --currentRollHysteresis;
+}
+
+void Dice::Roll() {
+ uint8_t resultIndividual;
+ uint16_t resultTotal = 0;
+ std::uniform_int_distribution<> distrib(1, dCounter.GetValue());
+
+ lv_label_set_text(resultIndividualLabel, "");
+
+ if (nCounter.GetValue() == 1) {
+ resultTotal = distrib(gen);
+ if (dCounter.GetValue() == 2) {
+ switch (resultTotal) {
+ case 1:
+ lv_label_set_text(resultIndividualLabel, "HEADS");
+ break;
+ case 2:
+ lv_label_set_text(resultIndividualLabel, "TAILS");
+ break;
+ }
+ }
+ } else {
+ for (uint8_t i = 0; i < nCounter.GetValue(); i++) {
+ resultIndividual = distrib(gen);
+ resultTotal += resultIndividual;
+ lv_label_ins_text(resultIndividualLabel, LV_LABEL_POS_LAST, std::to_string(resultIndividual).c_str());
+ if (i < (nCounter.GetValue() - 1)) {
+ lv_label_ins_text(resultIndividualLabel, LV_LABEL_POS_LAST, "+");
+ }
+ }
+ }
+
+ lv_label_set_text_fmt(resultTotalLabel, "%d", resultTotal);
+ if (openingRoll == false) {
+ motorController.RunForDuration(30);
+ NextColor();
+ currentRollHysteresis = rollHysteresis;
+ }
+}
+
+void Dice::NextColor() {
+ currentColorIndex = (currentColorIndex + 1) % resultColors.size();
+ lv_obj_set_style_local_text_color(resultTotalLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, resultColors[currentColorIndex]);
+ lv_obj_set_style_local_text_color(resultIndividualLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, resultColors[currentColorIndex]);
+}
diff --git a/src/displayapp/screens/Dice.h b/src/displayapp/screens/Dice.h
new file mode 100644
index 00000000..da91657d
--- /dev/null
+++ b/src/displayapp/screens/Dice.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "displayapp/apps/Apps.h"
+#include "displayapp/screens/Screen.h"
+#include "displayapp/widgets/Counter.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
+
+#include <array>
+#include <random>
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ class Dice : public Screen {
+ public:
+ Dice(Controllers::MotionController& motionController,
+ Controllers::MotorController& motorController,
+ Controllers::Settings& settingsController);
+ ~Dice() override;
+ void Roll();
+ void Refresh() override;
+
+ private:
+ lv_obj_t* btnRoll;
+ lv_obj_t* btnRollLabel;
+ lv_obj_t* resultTotalLabel;
+ lv_obj_t* resultIndividualLabel;
+ lv_task_t* refreshTask;
+ bool enableShakeForDice = false;
+
+ std::mt19937 gen;
+
+ std::array<lv_color_t, 3> resultColors = {LV_COLOR_YELLOW, LV_COLOR_MAGENTA, LV_COLOR_AQUA};
+ uint8_t currentColorIndex;
+ void NextColor();
+
+ Widgets::Counter nCounter = Widgets::Counter(1, 9, jetbrains_mono_42);
+ Widgets::Counter dCounter = Widgets::Counter(2, 99, jetbrains_mono_42);
+
+ bool openingRoll = true;
+ uint8_t currentRollHysteresis = 0;
+ static constexpr uint8_t rollHysteresis = 10;
+
+ Controllers::MotorController& motorController;
+ Controllers::MotionController& motionController;
+ Controllers::Settings& settingsController;
+ };
+ }
+
+ template <>
+ struct AppTraits<Apps::Dice> {
+ static constexpr Apps app = Apps::Dice;
+ static constexpr const char* icon = Screens::Symbols::dice;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Dice(controllers.motionController, controllers.motorController, controllers.settingsController);
+ };
+ };
+ }
+}
diff --git a/src/displayapp/screens/FirmwareUpdate.cpp b/src/displayapp/screens/FirmwareUpdate.cpp
index c40240c9..7d00ef39 100644
--- a/src/displayapp/screens/FirmwareUpdate.cpp
+++ b/src/displayapp/screens/FirmwareUpdate.cpp
@@ -2,6 +2,7 @@
#include <lvgl/lvgl.h>
#include "components/ble/BleController.h"
#include "displayapp/DisplayApp.h"
+#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -12,6 +13,9 @@ FirmwareUpdate::FirmwareUpdate(const Pinetime::Controllers::Ble& bleController)
lv_obj_align(titleLabel, nullptr, LV_ALIGN_IN_TOP_MID, 0, 50);
bar1 = lv_bar_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_bg_color(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt);
+ lv_obj_set_style_local_bg_opa(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
+ lv_obj_set_style_local_radius(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_size(bar1, 200, 30);
lv_obj_align(bar1, nullptr, LV_ALIGN_CENTER, 0, 0);
lv_bar_set_range(bar1, 0, 1000);
@@ -75,7 +79,7 @@ void FirmwareUpdate::DisplayProgression() const {
const uint32_t total = bleController.FirmwareUpdateTotalBytes();
const int16_t permille = current / (total / 1000);
- lv_label_set_text_fmt(percentLabel, "%d %%", permille / 10);
+ lv_label_set_text_fmt(percentLabel, "%d%%", permille / 10);
lv_bar_set_value(bar1, permille, LV_ANIM_OFF);
}
diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp
index 4a1b3d9f..2a9919d5 100644
--- a/src/displayapp/screens/FirmwareValidation.cpp
+++ b/src/displayapp/screens/FirmwareValidation.cpp
@@ -17,8 +17,8 @@ namespace {
FirmwareValidation::FirmwareValidation(Pinetime::Controllers::FirmwareValidator& validator) : validator {validator} {
labelVersion = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_fmt(labelVersion,
- "Version : %lu.%lu.%lu\n"
- "ShortRef : %s",
+ "Version: %lu.%lu.%lu\n"
+ "ShortRef: %s",
Version::Major(),
Version::Minor(),
Version::Patch(),
diff --git a/src/displayapp/screens/FlashLight.cpp b/src/displayapp/screens/FlashLight.cpp
index 1b7cf39c..7e0caff1 100644
--- a/src/displayapp/screens/FlashLight.cpp
+++ b/src/displayapp/screens/FlashLight.cpp
@@ -15,8 +15,9 @@ namespace {
}
FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessController& brightnessController)
- : systemTask {systemTask}, brightnessController {brightnessController} {
+ : wakeLock(systemTask), brightnessController {brightnessController} {
+ previousBrightnessLevel = brightnessController.Level();
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
flashLight = lv_label_create(lv_scr_act(), nullptr);
@@ -46,13 +47,13 @@ FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessCo
backgroundAction->user_data = this;
lv_obj_set_event_cb(backgroundAction, EventHandler);
- systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
+ wakeLock.Lock();
}
FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act());
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
- systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
+ brightnessController.Set(previousBrightnessLevel);
}
void FlashLight::SetColors() {
diff --git a/src/displayapp/screens/FlashLight.h b/src/displayapp/screens/FlashLight.h
index 2b710ed5..00ef4a7e 100644
--- a/src/displayapp/screens/FlashLight.h
+++ b/src/displayapp/screens/FlashLight.h
@@ -3,6 +3,7 @@
#include "displayapp/screens/Screen.h"
#include "components/brightness/BrightnessController.h"
#include "systemtask/SystemTask.h"
+#include "systemtask/WakeLock.h"
#include <cstdint>
#include <lvgl/lvgl.h>
@@ -23,10 +24,11 @@ namespace Pinetime {
void SetIndicators();
void SetColors();
- Pinetime::System::SystemTask& systemTask;
+ Pinetime::System::WakeLock wakeLock;
Controllers::BrightnessController& brightnessController;
Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High;
+ Controllers::BrightnessController::Levels previousBrightnessLevel;
lv_obj_t* flashLight;
lv_obj_t* backgroundAction;
diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp
index f611fa26..1a84d349 100644
--- a/src/displayapp/screens/HeartRate.cpp
+++ b/src/displayapp/screens/HeartRate.cpp
@@ -29,7 +29,7 @@ namespace {
}
HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, System::SystemTask& systemTask)
- : heartRateController {heartRateController}, systemTask {systemTask} {
+ : heartRateController {heartRateController}, wakeLock(systemTask) {
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
label_hr = lv_label_create(lv_scr_act(), nullptr);
@@ -41,7 +41,7 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
}
- lv_label_set_text_static(label_hr, "000");
+ lv_label_set_text_static(label_hr, "---");
lv_obj_align(label_hr, nullptr, LV_ALIGN_CENTER, 0, -40);
label_bpm = lv_label_create(lv_scr_act(), nullptr);
@@ -63,7 +63,7 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
label_startStop = lv_label_create(btn_startStop, nullptr);
UpdateStartStopButton(isHrRunning);
if (isHrRunning) {
- systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
+ wakeLock.Lock();
}
taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
@@ -72,7 +72,6 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
HeartRate::~HeartRate() {
lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
- systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
void HeartRate::Refresh() {
@@ -82,10 +81,14 @@ void HeartRate::Refresh() {
case Controllers::HeartRateController::States::NoTouch:
case Controllers::HeartRateController::States::NotEnoughData:
// case Controllers::HeartRateController::States::Stopped:
- lv_label_set_text_static(label_hr, "000");
+ lv_label_set_text_static(label_hr, "---");
break;
default:
- lv_label_set_text_fmt(label_hr, "%03d", heartRateController.HeartRate());
+ if (heartRateController.HeartRate() == 0) {
+ lv_label_set_text_static(label_hr, "---");
+ } else {
+ lv_label_set_text_fmt(label_hr, "%03d", heartRateController.HeartRate());
+ }
}
lv_label_set_text_static(label_status, ToString(state));
@@ -97,12 +100,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
heartRateController.Start();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
- systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
+ wakeLock.Lock();
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
} else {
heartRateController.Stop();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
- systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
+ wakeLock.Release();
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
}
}
diff --git a/src/displayapp/screens/HeartRate.h b/src/displayapp/screens/HeartRate.h
index 78ae63db..88b4918c 100644
--- a/src/displayapp/screens/HeartRate.h
+++ b/src/displayapp/screens/HeartRate.h
@@ -4,6 +4,8 @@
#include <chrono>
#include "displayapp/screens/Screen.h"
#include "systemtask/SystemTask.h"
+#include "systemtask/WakeLock.h"
+#include "Symbols.h"
#include <lvgl/src/lv_core/lv_style.h>
#include <lvgl/src/lv_core/lv_obj.h>
@@ -26,7 +28,7 @@ namespace Pinetime {
private:
Controllers::HeartRateController& heartRateController;
- Pinetime::System::SystemTask& systemTask;
+ Pinetime::System::WakeLock wakeLock;
void UpdateStartStopButton(bool isRunning);
lv_obj_t* label_hr;
lv_obj_t* label_bpm;
@@ -37,5 +39,15 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct AppTraits<Apps::HeartRate> {
+ static constexpr Apps app = Apps::HeartRate;
+ static constexpr const char* icon = Screens::Symbols::heartBeat;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::HeartRate(controllers.heartRateController, *controllers.systemTask);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/InfiniPaint.h b/src/displayapp/screens/InfiniPaint.h
index ec184c44..b1f9741a 100644
--- a/src/displayapp/screens/InfiniPaint.h
+++ b/src/displayapp/screens/InfiniPaint.h
@@ -5,6 +5,9 @@
#include <algorithm> // std::fill
#include "displayapp/screens/Screen.h"
#include "components/motor/MotorController.h"
+#include "Symbols.h"
+#include "displayapp/apps/Apps.h"
+#include <displayapp/Controllers.h>
namespace Pinetime {
namespace Components {
@@ -35,5 +38,15 @@ namespace Pinetime {
uint8_t color = 2;
};
}
+
+ template <>
+ struct AppTraits<Apps::Paint> {
+ static constexpr Apps app = Apps::Paint;
+ static constexpr const char* icon = Screens::Symbols::paintbrush;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::InfiniPaint(controllers.lvgl, controllers.motorController);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/List.h b/src/displayapp/screens/List.h
index 564229e6..17a25f82 100644
--- a/src/displayapp/screens/List.h
+++ b/src/displayapp/screens/List.h
@@ -5,7 +5,7 @@
#include <array>
#include "displayapp/screens/Screen.h"
#include "displayapp/widgets/PageIndicator.h"
-#include "displayapp/Apps.h"
+#include "displayapp/apps/Apps.h"
#include "components/settings/Settings.h"
#define MAXLISTITEMS 4
diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp
index 314fde73..6b758470 100644
--- a/src/displayapp/screens/Metronome.cpp
+++ b/src/displayapp/screens/Metronome.cpp
@@ -22,7 +22,7 @@ namespace {
}
Metronome::Metronome(Controllers::MotorController& motorController, System::SystemTask& systemTask)
- : motorController {motorController}, systemTask {systemTask} {
+ : motorController {motorController}, wakeLock(systemTask) {
bpmArc = lv_arc_create(lv_scr_act(), nullptr);
bpmArc->user_data = this;
@@ -72,7 +72,6 @@ Metronome::Metronome(Controllers::MotorController& motorController, System::Syst
Metronome::~Metronome() {
lv_task_del(taskRefresh);
- systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
@@ -128,12 +127,12 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
metronomeStarted = !metronomeStarted;
if (metronomeStarted) {
lv_label_set_text_static(lblPlayPause, Symbols::pause);
- systemTask.PushMessage(System::Messages::DisableSleeping);
+ wakeLock.Lock();
startTime = xTaskGetTickCount();
counter = 1;
} else {
lv_label_set_text_static(lblPlayPause, Symbols::play);
- systemTask.PushMessage(System::Messages::EnableSleeping);
+ wakeLock.Release();
}
}
break;
diff --git a/src/displayapp/screens/Metronome.h b/src/displayapp/screens/Metronome.h
index 13b0d664..fab7ff87 100644
--- a/src/displayapp/screens/Metronome.h
+++ b/src/displayapp/screens/Metronome.h
@@ -1,8 +1,10 @@
#pragma once
#include "systemtask/SystemTask.h"
+#include "systemtask/WakeLock.h"
#include "components/motor/MotorController.h"
#include "displayapp/screens/Screen.h"
+#include "Symbols.h"
namespace Pinetime {
namespace Applications {
@@ -20,7 +22,7 @@ namespace Pinetime {
TickType_t startTime = 0;
TickType_t tappedTime = 0;
Controllers::MotorController& motorController;
- System::SystemTask& systemTask;
+ System::WakeLock wakeLock;
int16_t bpm = 120;
uint8_t bpb = 4;
uint8_t counter = 1;
@@ -36,5 +38,15 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct AppTraits<Apps::Metronome> {
+ static constexpr Apps app = Apps::Metronome;
+ static constexpr const char* icon = Screens::Symbols::drum;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Metronome(controllers.motorController, *controllers.systemTask);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp
index 87c55eea..ecbed317 100644
--- a/src/displayapp/screens/Motion.cpp
+++ b/src/displayapp/screens/Motion.cpp
@@ -53,9 +53,9 @@ void Motion::Refresh() {
lv_label_set_text_fmt(labelStep, "Steps %lu", motionController.NbSteps());
lv_label_set_text_fmt(label,
- "X #FF0000 %d# Y #00B000 %d# Z #FFFF00 %d#",
- motionController.X() / 0x10,
- motionController.Y() / 0x10,
- motionController.Z() / 0x10);
+ "X #FF0000 %d# Y #00B000 %d# Z #FFFF00 %d# mg",
+ motionController.X(),
+ motionController.Y(),
+ motionController.Z());
lv_obj_align(label, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10);
}
diff --git a/src/displayapp/screens/Motion.h b/src/displayapp/screens/Motion.h
index e4cbe483..e13e068c 100644
--- a/src/displayapp/screens/Motion.h
+++ b/src/displayapp/screens/Motion.h
@@ -6,6 +6,8 @@
#include <lvgl/src/lv_core/lv_style.h>
#include <lvgl/src/lv_core/lv_obj.h>
#include <components/motion/MotionController.h>
+#include "displayapp/Controllers.h"
+#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Applications {
@@ -30,5 +32,15 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct AppTraits<Apps::Motion> {
+ static constexpr Apps app = Apps::Motion;
+ static constexpr const char* icon = "M";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Motion(controllers.motionController);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h
index 847c6e74..52253321 100644
--- a/src/displayapp/screens/Music.h
+++ b/src/displayapp/screens/Music.h
@@ -21,6 +21,9 @@
#include <lvgl/src/lv_core/lv_obj.h>
#include <string>
#include "displayapp/screens/Screen.h"
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
namespace Pinetime {
namespace Controllers {
@@ -82,5 +85,15 @@ namespace Pinetime {
/** Watchapp */
};
}
+
+ template <>
+ struct AppTraits<Apps::Music> {
+ static constexpr Apps app = Apps::Music;
+ static constexpr const char* icon = Screens::Symbols::music;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Music(*controllers.musicService);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/Navigation.cpp b/src/displayapp/screens/Navigation.cpp
index 7baea09d..ee9f2a00 100644
--- a/src/displayapp/screens/Navigation.cpp
+++ b/src/displayapp/screens/Navigation.cpp
@@ -23,105 +23,166 @@
using namespace Pinetime::Applications::Screens;
-LV_FONT_DECLARE(lv_font_navi_80)
+/* Notes about the navigation icons :
+ * - Icons are generated from a TTF font converted in PNG images. Those images are all appended
+ * vertically into a single PNG images. Since LVGL support images width and height up to
+ * 2048 px, the icons needs to be split into 2 separate PNG pictures. More info in
+ * src/displayapp/fonts/README.md
+ * - To make the handling of those icons easier, they must all have the same width and height
+ * - Those PNG are then converted into BINARY format using the classical image generator
+ * (in src/resources/generate-img.py)
+ * - The array `iconMap` maps each icon with an index. This index corresponds to the position of
+ * the icon in the file. All index lower than 25 (`maxIconsPerFile`) represent icons located
+ * in the first file (navigation0.bin). All the other icons are located in the second file
+ * (navigation1.bin). Since all icons have the same height, this index must be multiplied by
+ * 80px (`iconHeight`) to get the actual position (in pixels) of the icon in the image.
+ * - This is how the images are laid out in the PNG files :
+ * *---------------*
+ * | ICON 0 |
+ * | FILE 0 |
+ * | INDEX = 0 |
+ * | PIXEL# = 0 |
+ * *---------------*
+ * | ICON 1 |
+ * | FILE 0 |
+ * | INDEX = 1 |
+ * | PIXEL# = -80 |
+ * *---------------*
+ * | ICON 2 |
+ * | FILE 0 |
+ * | INDEX = 2 |
+ * | PIXEL# = -160 |
+ * *---------------*
+ * | ... |
+ * *---------------*
+ * | ICON 25 |
+ * | FILE 1 |
+ * | INDEX = 25 |
+ * | PIXEL# = 0 |
+ * *---------------*
+ * | ICON 26 |
+ * | FILE 1 |
+ * | INDEX = 26 |
+ * | PIXEL# = -80 |
+ * *---------------*
+ * - The source images are located in `src/resources/navigation0.png` and `src/resources/navigation1.png`
+ */
namespace {
- constexpr std::array<std::pair<const char*, const char*>, 86> m_iconMap = {{
- {"arrive-left", "\xEE\xA4\x81"},
- {"arrive-right", "\xEE\xA4\x82"},
- {"arrive-straight", "\xEE\xA4\x80"},
- {"arrive", "\xEE\xA4\x80"},
- {"close", "\xEE\xA4\x83"},
- {"continue-left", "\xEE\xA4\x85"},
- {"continue-right", "\xEE\xA4\x86"},
- {"continue-slight-left", "\xEE\xA4\x87"},
- {"continue-slight-right", "\xEE\xA4\x88"},
- {"continue-straight", "\xEE\xA4\x84"},
- {"continue-uturn", "\xEE\xA4\x89"},
- {"continue", "\xEE\xA4\x84"},
- {"depart-left", "\xEE\xA4\x8B"},
- {"depart-right", "\xEE\xA4\x8C"},
- {"depart-straight", "\xEE\xA4\x8A"},
- {"end-of-road-left", "\xEE\xA4\x8D"},
- {"end-of-road-right", "\xEE\xA4\x8E"},
- {"ferry", "\xEE\xA4\x8F"},
- {"flag", "\xEE\xA4\x90"},
- {"fork-left", "\xEE\xA4\x92"},
- {"fork-right", "\xEE\xA4\x93"},
- {"fork-slight-left", "\xEE\xA4\x94"},
- {"fork-slight-right", "\xEE\xA4\x95"},
- {"fork-straight", "\xEE\xA4\x96"},
- {"invalid", "\xEE\xA4\x84"},
- {"invalid-left", "\xEE\xA4\x85"},
- {"invalid-right", "\xEE\xA4\x86"},
- {"invalid-slight-left", "\xEE\xA4\x87"},
- {"invalid-slight-right", "\xEE\xA4\x88"},
- {"invalid-straight", "\xEE\xA4\x84"},
- {"invalid-uturn", "\xEE\xA4\x89"},
- {"merge-left", "\xEE\xA4\x97"},
- {"merge-right", "\xEE\xA4\x98"},
- {"merge-slight-left", "\xEE\xA4\x99"},
- {"merge-slight-right", "\xEE\xA4\x9A"},
- {"merge-straight", "\xEE\xA4\x84"},
- {"new-name-left", "\xEE\xA4\x85"},
- {"new-name-right", "\xEE\xA4\x86"},
- {"new-name-sharp-left", "\xEE\xA4\x9B"},
- {"new-name-sharp-right", "\xEE\xA4\x9C"},
- {"new-name-slight-left", "\xEE\xA4\x87"},
- {"new-name-slight-right", "\xEE\xA4\x88"},
- {"new-name-straight", "\xEE\xA4\x84"},
- {"notification-left", "\xEE\xA4\x85"},
- {"notification-right", "\xEE\xA4\x86"},
- {"notification-sharp-left", "\xEE\xA4\x9B"},
- {"notification-sharp-right", "\xEE\xA4\xA5"},
- {"notification-slight-left", "\xEE\xA4\x87"},
- {"notification-slight-right", "\xEE\xA4\x88"},
- {"notification-straight", "\xEE\xA4\x84"},
- {"off-ramp-left", "\xEE\xA4\x9D"},
- {"off-ramp-right", "\xEE\xA4\x9E"},
- {"off-ramp-slight-left", "\xEE\xA4\x9F"},
- {"off-ramp-slight-right", "\xEE\xA4\xA0"},
- {"on-ramp-left", "\xEE\xA4\x85"},
- {"on-ramp-right", "\xEE\xA4\x86"},
- {"on-ramp-sharp-left", "\xEE\xA4\x9B"},
- {"on-ramp-sharp-right", "\xEE\xA4\xA5"},
- {"on-ramp-slight-left", "\xEE\xA4\x87"},
- {"on-ramp-slight-right", "\xEE\xA4\x88"},
- {"on-ramp-straight", "\xEE\xA4\x84"},
- {"rotary", "\xEE\xA4\xA1"},
- {"rotary-left", "\xEE\xA4\xA2"},
- {"rotary-right", "\xEE\xA4\xA3"},
- {"rotary-sharp-left", "\xEE\xA4\xA4"},
- {"rotary-sharp-right", "\xEE\xA4\xA5"},
- {"rotary-slight-left", "\xEE\xA4\xA6"},
- {"rotary-slight-right", "\xEE\xA4\xA7"},
- {"rotary-straight", "\xEE\xA4\xA8"},
- {"roundabout", "\xEE\xA4\xA1"},
- {"roundabout-left", "\xEE\xA4\xA2"},
- {"roundabout-right", "\xEE\xA4\xA3"},
- {"roundabout-sharp-left", "\xEE\xA4\xA4"},
- {"roundabout-sharp-right", "\xEE\xA4\xA5"},
- {"roundabout-slight-left", "\xEE\xA4\xA6"},
- {"roundabout-slight-right", "\xEE\xA4\xA7"},
- {"roundabout-straight", "\xEE\xA4\xA8"},
- {"turn-left", "\xEE\xA4\x85"},
- {"turn-right", "\xEE\xA4\x86"},
- {"turn-sharp-left", "\xEE\xA4\x9B"},
- {"turn-sharp-right", "\xEE\xA4\xA5"},
- {"turn-slight-left", "\xEE\xA4\x87"},
- {"turn-slight-right", "\xEE\xA4\x88"},
- {"turn-straight", "\xEE\xA4\x84"},
- {"updown", "\xEE\xA4\xA9"},
- {"uturn", "\xEE\xA4\x89"},
+ struct Icon {
+ const char* fileName;
+ int16_t offset;
+ };
+
+ constexpr uint16_t iconHeight = -80;
+ constexpr uint8_t flagIndex = 18;
+ constexpr uint8_t maxIconsPerFile = 25;
+ const char* iconsFile0 = "F:/images/navigation0.bin";
+ const char* iconsFile1 = "F:/images/navigation1.bin";
+
+ constexpr std::array<std::pair<const char*, uint8_t>, 86> iconMap = {{
+ {"arrive-left", 1},
+ {"arrive-right", 2},
+ {"arrive-straight", 0},
+ {"arrive", 0},
+ {"close", 3},
+ {"continue-left", 5},
+ {"continue-right", 6},
+ {"continue-slight-left", 7},
+ {"continue-slight-right", 8},
+ {"continue-straight", 4},
+ {"continue-uturn", 9},
+ {"continue", 4},
+ {"depart-left", 11},
+ {"depart-right", 12},
+ {"depart-straight", 10},
+ {"end-of-road-left", 13},
+ {"end-of-road-right", 14},
+ {"ferry", 15},
+ {"flag", 16},
+ {"fork-left", 18},
+ {"fork-right", 19},
+ {"fork-slight-left", 20},
+ {"fork-slight-right", 21},
+ {"fork-straight", 22},
+ {"invalid", 4},
+ {"invalid-left", 5},
+ {"invalid-right", 6},
+ {"invalid-slight-left", 7},
+ {"invalid-slight-right", 8},
+ {"invalid-straight", 4},
+ {"invalid-uturn", 9},
+ {"merge-left", 23},
+ {"merge-right", 24},
+ {"merge-slight-left", 25},
+ {"merge-slight-right", 26},
+ {"merge-straight", 4},
+ {"new-name-left", 5},
+ {"new-name-right", 6},
+ {"new-name-sharp-left", 27},
+ {"new-name-sharp-right", 28},
+ {"new-name-slight-left", 7},
+ {"new-name-slight-right", 8},
+ {"new-name-straight", 4},
+ {"notification-left", 5},
+ {"notification-right", 6},
+ {"notification-sharp-left", 27},
+ {"notification-sharp-right", 37},
+ {"notification-slight-left", 7},
+ {"notification-slight-right", 8},
+ {"notification-straight", 4},
+ {"off-ramp-left", 29},
+ {"off-ramp-right", 30},
+ {"off-ramp-slight-left", 31},
+ {"off-ramp-slight-right", 32},
+ {"on-ramp-left", 5},
+ {"on-ramp-right", 6},
+ {"on-ramp-sharp-left", 27},
+ {"on-ramp-sharp-right", 37},
+ {"on-ramp-slight-left", 7},
+ {"on-ramp-slight-right", 8},
+ {"on-ramp-straight", 4},
+ {"rotary", 33},
+ {"rotary-left", 34},
+ {"rotary-right", 35},
+ {"rotary-sharp-left", 36},
+ {"rotary-sharp-right", 37},
+ {"rotary-slight-left", 38},
+ {"rotary-slight-right", 39},
+ {"rotary-straight", 40},
+ {"roundabout", 33},
+ {"roundabout-left", 34},
+ {"roundabout-right", 35},
+ {"roundabout-sharp-left", 36},
+ {"roundabout-sharp-right", 37},
+ {"roundabout-slight-left", 38},
+ {"roundabout-slight-right", 39},
+ {"roundabout-straight", 40},
+ {"turn-left", 5},
+ {"turn-right", 6},
+ {"turn-sharp-left", 27},
+ {"turn-sharp-right", 37},
+ {"turn-slight-left", 7},
+ {"turn-slight-right", 8},
+ {"turn-straight", 4},
+ {"updown", 41},
+ {"uturn", 9},
}};
- const char* iconForName(const std::string& icon) {
- for (auto iter : m_iconMap) {
+ Icon GetIcon(uint8_t index) {
+ if (index < maxIconsPerFile) {
+ return {iconsFile0, static_cast<int16_t>(iconHeight * index)};
+ }
+ return {iconsFile1, static_cast<int16_t>(iconHeight * (index - maxIconsPerFile))};
+ }
+
+ Icon GetIcon(const std::string& icon) {
+ for (const auto& iter : iconMap) {
if (iter.first == icon) {
- return iter.second;
+ return GetIcon(iter.second);
}
}
- return "\xEE\xA4\x90";
+ return GetIcon(flagIndex);
}
}
@@ -130,27 +191,33 @@ namespace {
*
*/
Navigation::Navigation(Pinetime::Controllers::NavigationService& nav) : navService(nav) {
-
- imgFlag = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_set_style_local_text_font(imgFlag, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_navi_80);
- lv_obj_set_style_local_text_color(imgFlag, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
- lv_label_set_text_static(imgFlag, iconForName("flag"));
+ const auto& image = GetIcon("flag");
+ imgFlag = lv_img_create(lv_scr_act(), nullptr);
+ lv_img_set_auto_size(imgFlag, false);
+ lv_obj_set_size(imgFlag, 80, 80);
+ lv_img_set_src(imgFlag, image.fileName);
+ lv_img_set_offset_x(imgFlag, 0);
+ lv_img_set_offset_y(imgFlag, image.offset);
+ lv_obj_set_style_local_image_recolor_opa(imgFlag, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
+ lv_obj_set_style_local_image_recolor(imgFlag, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
lv_obj_align(imgFlag, nullptr, LV_ALIGN_CENTER, 0, -60);
txtNarrative = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_long_mode(txtNarrative, LV_LABEL_LONG_BREAK);
+ lv_label_set_long_mode(txtNarrative, LV_LABEL_LONG_DOT);
lv_obj_set_width(txtNarrative, LV_HOR_RES);
+ lv_obj_set_height(txtNarrative, 80);
lv_label_set_text_static(txtNarrative, "Navigation");
lv_label_set_align(txtNarrative, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(txtNarrative, nullptr, LV_ALIGN_CENTER, 0, 10);
+ lv_obj_align(txtNarrative, nullptr, LV_ALIGN_CENTER, 0, 30);
txtManDist = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_long_mode(txtManDist, LV_LABEL_LONG_BREAK);
lv_obj_set_style_local_text_color(txtManDist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
+ lv_obj_set_style_local_text_font(txtManDist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_obj_set_width(txtManDist, LV_HOR_RES);
lv_label_set_text_static(txtManDist, "--M");
lv_label_set_align(txtManDist, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(txtManDist, nullptr, LV_ALIGN_CENTER, 0, 60);
+ lv_obj_align(txtManDist, nullptr, LV_ALIGN_CENTER, 0, 90);
// Route Progress
barProgress = lv_bar_create(lv_scr_act(), nullptr);
@@ -173,7 +240,11 @@ Navigation::~Navigation() {
void Navigation::Refresh() {
if (flag != navService.getFlag()) {
flag = navService.getFlag();
- lv_label_set_text_static(imgFlag, iconForName(flag));
+ const auto& image = GetIcon(flag);
+ lv_img_set_src(imgFlag, image.fileName);
+ lv_obj_set_style_local_image_recolor_opa(imgFlag, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
+ lv_obj_set_style_local_image_recolor(imgFlag, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_CYAN);
+ lv_img_set_offset_y(imgFlag, image.offset);
}
if (narrative != navService.getNarrative()) {
@@ -196,3 +267,19 @@ void Navigation::Refresh() {
}
}
}
+
+bool Navigation::IsAvailable(Pinetime::Controllers::FS& filesystem) {
+ lfs_file file = {};
+
+ if (filesystem.FileOpen(&file, "/images/navigation0.bin", LFS_O_RDONLY) < 0) {
+ return false;
+ }
+ filesystem.FileClose(&file);
+
+ if (filesystem.FileOpen(&file, "/images/navigation1.bin", LFS_O_RDONLY) < 0) {
+ return false;
+ }
+ filesystem.FileClose(&file);
+
+ return true;
+}
diff --git a/src/displayapp/screens/Navigation.h b/src/displayapp/screens/Navigation.h
index 6495edb2..5c7a0429 100644
--- a/src/displayapp/screens/Navigation.h
+++ b/src/displayapp/screens/Navigation.h
@@ -22,20 +22,25 @@
#include <string>
#include "displayapp/screens/Screen.h"
#include <array>
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
namespace Pinetime {
namespace Controllers {
class NavigationService;
+ class FS;
}
namespace Applications {
namespace Screens {
class Navigation : public Screen {
public:
- Navigation(Pinetime::Controllers::NavigationService& nav);
+ explicit Navigation(Pinetime::Controllers::NavigationService& nav);
~Navigation() override;
void Refresh() override;
+ static bool IsAvailable(Pinetime::Controllers::FS& filesystem);
private:
lv_obj_t* imgFlag;
@@ -48,10 +53,20 @@ namespace Pinetime {
std::string flag;
std::string narrative;
std::string manDist;
- int progress;
+ int progress = 0;
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct AppTraits<Apps::Navigation> {
+ static constexpr Apps app = Apps::Navigation;
+ static constexpr const char* icon = Screens::Symbols::map;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Navigation(*controllers.navigationService);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp
index 037c43a7..837c4683 100644
--- a/src/displayapp/screens/Notifications.cpp
+++ b/src/displayapp/screens/Notifications.cpp
@@ -20,7 +20,7 @@ Notifications::Notifications(DisplayApp* app,
notificationManager {notificationManager},
alertNotificationService {alertNotificationService},
motorController {motorController},
- systemTask {systemTask},
+ wakeLock(systemTask),
mode {mode} {
notificationManager.ClearNewNotificationFlag();
@@ -40,7 +40,7 @@ Notifications::Notifications(DisplayApp* app,
validDisplay = false;
}
if (mode == Modes::Preview) {
- systemTask.PushMessage(System::Messages::DisableSleeping);
+ wakeLock.Lock();
if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) {
motorController.StartRinging();
} else {
@@ -65,7 +65,6 @@ Notifications::~Notifications() {
lv_task_del(taskRefresh);
// make sure we stop any vibrations before exiting
motorController.StopRinging();
- systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
@@ -82,7 +81,6 @@ void Notifications::Refresh() {
} else if (mode == Modes::Preview && dismissingNotification) {
running = false;
- currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
} else if (dismissingNotification) {
dismissingNotification = false;
@@ -113,15 +111,15 @@ void Notifications::Refresh() {
alertNotificationService,
motorController);
} else {
- currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
+ running = false;
}
}
- running = currentItem->IsRunning() && running;
+ running = running && currentItem->IsRunning();
}
void Notifications::OnPreviewInteraction() {
- systemTask.PushMessage(System::Messages::EnableSleeping);
+ wakeLock.Release();
motorController.StopRinging();
if (timeoutLine != nullptr) {
lv_obj_del(timeoutLine);
@@ -173,7 +171,9 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
} else if (nextMessage.valid) {
currentId = nextMessage.id;
} else {
- // don't update id, won't be found be refresh and try to load latest message or no message box
+ // don't update id, notification manager will try to fetch
+ // but not find it. Refresh will try to load latest message
+ // or dismiss to watchface
}
DismissToBlack();
return true;
@@ -246,8 +246,8 @@ namespace {
Notifications::NotificationItem::NotificationItem(Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController)
- : NotificationItem("Notification",
- "No notification to display",
+ : NotificationItem("Notifications",
+ "No notifications to display",
0,
Controllers::NotificationManager::Categories::Unknown,
0,
diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h
index 114316b3..8488dc5b 100644
--- a/src/displayapp/screens/Notifications.h
+++ b/src/displayapp/screens/Notifications.h
@@ -8,6 +8,7 @@
#include "components/ble/NotificationManager.h"
#include "components/motor/MotorController.h"
#include "systemtask/SystemTask.h"
+#include "systemtask/WakeLock.h"
namespace Pinetime {
namespace Controllers {
@@ -73,7 +74,7 @@ namespace Pinetime {
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
Pinetime::Controllers::MotorController& motorController;
- System::SystemTask& systemTask;
+ System::WakeLock wakeLock;
Modes mode = Modes::Normal;
std::unique_ptr<NotificationItem> currentItem;
Pinetime::Controllers::NotificationManager::Notification::Id currentId;
diff --git a/src/displayapp/screens/Paddle.h b/src/displayapp/screens/Paddle.h
index 33dac191..586cccf4 100644
--- a/src/displayapp/screens/Paddle.h
+++ b/src/displayapp/screens/Paddle.h
@@ -3,6 +3,9 @@
#include <lvgl/lvgl.h>
#include <cstdint>
#include "displayapp/screens/Screen.h"
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
namespace Pinetime {
namespace Components {
@@ -45,5 +48,15 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct AppTraits<Apps::Paddle> {
+ static constexpr Apps app = Apps::Paddle;
+ static constexpr const char* icon = Screens::Symbols::paddle;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Paddle(controllers.lvgl);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h
index 09bd6131..9f6e0ede 100644
--- a/src/displayapp/screens/Screen.h
+++ b/src/displayapp/screens/Screen.h
@@ -9,41 +9,6 @@ namespace Pinetime {
class DisplayApp;
namespace Screens {
-
- template <class T>
- class DirtyValue {
- public:
- DirtyValue() = default; // Use NSDMI
-
- explicit DirtyValue(T const& v) : value {v} {
- } // Use MIL and const-lvalue-ref
-
- bool IsUpdated() {
- if (this->isUpdated) {
- this->isUpdated = false;
- return true;
- }
- return false;
- }
-
- T const& Get() {
- this->isUpdated = false;
- return value;
- } // never expose a non-const lvalue-ref
-
- DirtyValue& operator=(const T& other) {
- if (this->value != other) {
- this->value = other;
- this->isUpdated = true;
- }
- return *this;
- }
-
- private:
- T value {}; // NSDMI - default initialise type
- bool isUpdated {true}; // NSDMI - use brace initialisation
- };
-
class Screen {
private:
virtual void Refresh() {
diff --git a/src/displayapp/screens/Steps.h b/src/displayapp/screens/Steps.h
index 5dc07eff..6443582f 100644
--- a/src/displayapp/screens/Steps.h
+++ b/src/displayapp/screens/Steps.h
@@ -4,6 +4,9 @@
#include <lvgl/lvgl.h>
#include "displayapp/screens/Screen.h"
#include <components/motion/MotionController.h>
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
namespace Pinetime {
@@ -39,5 +42,15 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct AppTraits<Apps::Steps> {
+ static constexpr Apps app = Apps::Steps;
+ static constexpr const char* icon = Screens::Symbols::shoe;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Steps(controllers.motionController, controllers.settingsController);
+ };
+ };
}
}
diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp
index 72904c88..ff852beb 100644
--- a/src/displayapp/screens/StopWatch.cpp
+++ b/src/displayapp/screens/StopWatch.cpp
@@ -12,8 +12,9 @@ namespace {
const int hundredths = (timeElapsedCentis % 100);
const int secs = (timeElapsedCentis / 100) % 60;
- const int mins = (timeElapsedCentis / 100) / 60;
- return TimeSeparated_t {mins, secs, hundredths};
+ const int mins = ((timeElapsedCentis / 100) / 60) % 60;
+ const int hours = ((timeElapsedCentis / 100) / 60) / 60;
+ return TimeSeparated_t {hours, mins, secs, hundredths};
}
void play_pause_event_handler(lv_obj_t* obj, lv_event_t event) {
@@ -33,7 +34,7 @@ namespace {
constexpr TickType_t blinkInterval = pdMS_TO_TICKS(1000);
}
-StopWatch::StopWatch(System::SystemTask& systemTask) : systemTask {systemTask} {
+StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) {
static constexpr uint8_t btnWidth = 115;
static constexpr uint8_t btnHeight = 80;
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
@@ -78,7 +79,6 @@ StopWatch::StopWatch(System::SystemTask& systemTask) : systemTask {systemTask} {
StopWatch::~StopWatch() {
lv_task_del(taskRefresh);
- systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act());
}
@@ -110,6 +110,12 @@ void StopWatch::SetInterfaceStopped() {
lv_label_set_text_static(time, "00:00");
lv_label_set_text_static(msecTime, "00");
+ if (isHoursLabelUpdated) {
+ lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
+ lv_obj_realign(time);
+ isHoursLabelUpdated = false;
+ }
+
lv_label_set_text_static(lapText, "");
lv_label_set_text_static(txtPlayPause, Symbols::play);
lv_label_set_text_static(txtStopLap, Symbols::lapsFlag);
@@ -128,7 +134,7 @@ void StopWatch::Start() {
SetInterfaceRunning();
startTime = xTaskGetTickCount();
currentState = States::Running;
- systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
+ wakeLock.Lock();
}
void StopWatch::Pause() {
@@ -138,7 +144,7 @@ void StopWatch::Pause() {
oldTimeElapsed = laps[lapsDone];
blinkTime = xTaskGetTickCount() + blinkInterval;
currentState = States::Halted;
- systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
+ wakeLock.Release();
}
void StopWatch::Refresh() {
@@ -146,7 +152,16 @@ void StopWatch::Refresh() {
laps[lapsDone] = oldTimeElapsed + xTaskGetTickCount() - startTime;
TimeSeparated_t currentTimeSeparated = convertTicksToTimeSegments(laps[lapsDone]);
- lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
+ if (currentTimeSeparated.hours == 0) {
+ lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
+ } else {
+ lv_label_set_text_fmt(time, "%02d:%02d:%02d", currentTimeSeparated.hours, currentTimeSeparated.mins, currentTimeSeparated.secs);
+ if (!isHoursLabelUpdated) {
+ lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_obj_realign(time);
+ isHoursLabelUpdated = true;
+ }
+ }
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
} else if (currentState == States::Halted) {
const TickType_t currentTime = xTaskGetTickCount();
@@ -182,8 +197,12 @@ void StopWatch::stopLapBtnEventHandler() {
continue;
}
TimeSeparated_t times = convertTicksToTimeSegments(laps[i]);
- char buffer[16];
- sprintf(buffer, "#%2d %2d:%02d.%02d\n", i + 1, times.mins, times.secs, times.hundredths);
+ char buffer[17];
+ if (times.hours == 0) {
+ snprintf(buffer, sizeof(buffer), "#%2d %2d:%02d.%02d\n", i + 1, times.mins, times.secs, times.hundredths);
+ } else {
+ snprintf(buffer, sizeof(buffer), "#%2d %2d:%02d:%02d.%02d\n", i + 1, times.hours, times.mins, times.secs, times.hundredths);
+ }
lv_label_ins_text(lapText, LV_LABEL_POS_LAST, buffer);
}
} else if (currentState == States::Halted) {
diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h
index 409e3a19..55a178dc 100644
--- a/src/displayapp/screens/StopWatch.h
+++ b/src/displayapp/screens/StopWatch.h
@@ -7,48 +7,68 @@
#include "portmacro_cmsis.h"
#include "systemtask/SystemTask.h"
+#include "systemtask/WakeLock.h"
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
-namespace Pinetime::Applications::Screens {
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
- enum class States { Init, Running, Halted };
+ enum class States { Init, Running, Halted };
- struct TimeSeparated_t {
- int mins;
- int secs;
- int hundredths;
- };
+ struct TimeSeparated_t {
+ int hours;
+ int mins;
+ int secs;
+ int hundredths;
+ };
- class StopWatch : public Screen {
- public:
- explicit StopWatch(System::SystemTask& systemTask);
- ~StopWatch() override;
- void Refresh() override;
+ class StopWatch : public Screen {
+ public:
+ explicit StopWatch(System::SystemTask& systemTask);
+ ~StopWatch() override;
+ void Refresh() override;
- void playPauseBtnEventHandler();
- void stopLapBtnEventHandler();
- bool OnButtonPushed() override;
+ void playPauseBtnEventHandler();
+ void stopLapBtnEventHandler();
+ bool OnButtonPushed() override;
- private:
- void SetInterfacePaused();
- void SetInterfaceRunning();
- void SetInterfaceStopped();
+ private:
+ void SetInterfacePaused();
+ void SetInterfaceRunning();
+ void SetInterfaceStopped();
- void Reset();
- void Start();
- void Pause();
+ void Reset();
+ void Start();
+ void Pause();
- Pinetime::System::SystemTask& systemTask;
- States currentState = States::Init;
- TickType_t startTime;
- TickType_t oldTimeElapsed = 0;
- TickType_t blinkTime = 0;
- static constexpr int maxLapCount = 20;
- TickType_t laps[maxLapCount + 1];
- static constexpr int displayedLaps = 2;
- int lapsDone = 0;
- lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
- lv_obj_t* lapText;
+ Pinetime::System::WakeLock wakeLock;
+ States currentState = States::Init;
+ TickType_t startTime;
+ TickType_t oldTimeElapsed = 0;
+ TickType_t blinkTime = 0;
+ static constexpr int maxLapCount = 20;
+ TickType_t laps[maxLapCount + 1];
+ static constexpr int displayedLaps = 2;
+ int lapsDone = 0;
+ lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
+ lv_obj_t* lapText;
+ bool isHoursLabelUpdated = false;
- lv_task_t* taskRefresh;
- };
+ lv_task_t* taskRefresh;
+ };
+ }
+
+ template <>
+ struct AppTraits<Apps::StopWatch> {
+ static constexpr Apps app = Apps::StopWatch;
+ static constexpr const char* icon = Screens::Symbols::stopWatch;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::StopWatch(*controllers.systemTask);
+ };
+ };
+ }
}
diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h
index 934cdc3f..40699b3d 100644
--- a/src/displayapp/screens/Symbols.h
+++ b/src/displayapp/screens/Symbols.h
@@ -11,6 +11,7 @@ namespace Pinetime {
static constexpr const char* plug = "\xEF\x87\xA6";
static constexpr const char* shoe = "\xEF\x95\x8B";
static constexpr const char* clock = "\xEF\x80\x97";
+ static constexpr const char* bell = "\xEF\x83\xB3";
static constexpr const char* info = "\xEF\x84\xA9";
static constexpr const char* list = "\xEF\x80\xBA";
static constexpr const char* sun = "\xEF\x86\x85";
@@ -34,9 +35,24 @@ namespace Pinetime {
static constexpr const char* hourGlass = "\xEF\x89\x92";
static constexpr const char* lapsFlag = "\xEF\x80\xA4";
static constexpr const char* drum = "\xEF\x95\xA9";
+ static constexpr const char* dice = "\xEF\x94\xA2";
static constexpr const char* eye = "\xEF\x81\xAE";
static constexpr const char* home = "\xEF\x80\x95";
static constexpr const char* sleep = "\xEE\xBD\x84";
+ static constexpr const char* calculator = "\xEF\x87\xAC";
+ static constexpr const char* backspace = "\xEF\x95\x9A";
+
+ // fontawesome_weathericons.c
+ // static constexpr const char* sun = "\xEF\x86\x85";
+ static constexpr const char* cloudSun = "\xEF\x9B\x84";
+ static constexpr const char* cloudSunRain = "\xEF\x9D\x83";
+ static constexpr const char* cloudShowersHeavy = "\xEF\x9D\x80";
+ static constexpr const char* smog = "\xEF\x9D\x9F";
+ static constexpr const char* cloud = "\xEF\x83\x82";
+ static constexpr const char* cloudMeatball = "\xEF\x9C\xBB";
+ static constexpr const char* bolt = "\xEF\x83\xA7";
+ static constexpr const char* snowflake = "\xEF\x8B\x9C";
+ static constexpr const char* ban = "\xEF\x81\x9E";
// lv_font_sys_48.c
static constexpr const char* settings = "\xEE\xA2\xB8";
diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index 511ecf50..2392f3be 100644
--- a/src/displayapp/screens/SystemInfo.cpp
+++ b/src/displayapp/screens/SystemInfo.cpp
@@ -38,15 +38,16 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
const Pinetime::Controllers::Ble& bleController,
const Pinetime::Drivers::Watchdog& watchdog,
Pinetime::Controllers::MotionController& motionController,
- const Pinetime::Drivers::Cst816S& touchPanel)
- : app {app},
- dateTimeController {dateTimeController},
+ const Pinetime::Drivers::Cst816S& touchPanel,
+ const Pinetime::Drivers::SpiNorFlash& spiNorFlash)
+ : dateTimeController {dateTimeController},
batteryController {batteryController},
brightnessController {brightnessController},
bleController {bleController},
watchdog {watchdog},
motionController {motionController},
touchPanel {touchPanel},
+ spiNorFlash {spiNorFlash},
screens {app,
0,
{[this]() -> std::unique_ptr<Screen> {
@@ -101,24 +102,24 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() {
std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
auto batteryPercent = batteryController.PercentRemaining();
const auto* resetReason = [this]() {
- switch (watchdog.ResetReason()) {
- case Drivers::Watchdog::ResetReasons::Watchdog:
+ switch (watchdog.GetResetReason()) {
+ case Drivers::Watchdog::ResetReason::Watchdog:
return "wtdg";
- case Drivers::Watchdog::ResetReasons::HardReset:
+ case Drivers::Watchdog::ResetReason::HardReset:
return "hardr";
- case Drivers::Watchdog::ResetReasons::NFC:
+ case Drivers::Watchdog::ResetReason::NFC:
return "nfc";
- case Drivers::Watchdog::ResetReasons::SoftReset:
+ case Drivers::Watchdog::ResetReason::SoftReset:
return "softr";
- case Drivers::Watchdog::ResetReasons::CpuLockup:
+ case Drivers::Watchdog::ResetReason::CpuLockup:
return "cpulock";
- case Drivers::Watchdog::ResetReasons::SystemOff:
+ case Drivers::Watchdog::ResetReason::SystemOff:
return "off";
- case Drivers::Watchdog::ResetReasons::LpComp:
+ case Drivers::Watchdog::ResetReason::LpComp:
return "lpcomp";
- case Drivers::Watchdog::ResetReasons::DebugInterface:
+ case Drivers::Watchdog::ResetReason::DebugInterface:
return "dbg";
- case Drivers::Watchdog::ResetReasons::ResetPin:
+ case Drivers::Watchdog::ResetReason::ResetPin:
return "rst";
default:
return "?";
@@ -177,6 +178,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
return std::make_unique<Screens::Label>(1, 5, label);
}
+extern int mallocFailedCount;
+extern int stackOverflowCount;
std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
lv_mem_monitor_t mon;
lv_mem_monitor(&mon);
@@ -184,26 +187,32 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
const auto& bleAddr = bleController.Address();
+ auto spiFlashId = spiNorFlash.GetIdentification();
lv_label_set_text_fmt(label,
"#808080 BLE MAC#\n"
- " %02x:%02x:%02x:%02x:%02x:%02x"
+ " %02x:%02x:%02x:%02x:%02x:%02x\n"
"\n"
- "#808080 LVGL Memory#\n"
- " #808080 used# %d (%d%%)\n"
- " #808080 max used# %lu\n"
- " #808080 frag# %d%%\n"
- " #808080 free# %d",
+ "#808080 SPI Flash# %02x-%02x-%02x\n"
+ "\n"
+ "#808080 Memory heap#\n"
+ " #808080 Free# %d/%d\n"
+ " #808080 Min free# %d\n"
+ " #808080 Alloc err# %d\n"
+ " #808080 Ovrfl err# %d",
bleAddr[5],
bleAddr[4],
bleAddr[3],
bleAddr[2],
bleAddr[1],
bleAddr[0],
- static_cast<int>(mon.total_size - mon.free_size),
- mon.used_pct,
- mon.max_used,
- mon.frag_pct,
- static_cast<int>(mon.free_biggest_size));
+ spiFlashId.manufacturer,
+ spiFlashId.type,
+ spiFlashId.density,
+ xPortGetFreeHeapSize(),
+ xPortGetHeapSize(),
+ xPortGetMinimumEverFreeHeapSize(),
+ mallocFailedCount,
+ stackOverflowCount);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::make_unique<Screens::Label>(2, 5, label);
}
@@ -232,11 +241,16 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
lv_table_set_col_width(infoTask, 3, 90);
auto nb = uxTaskGetSystemState(tasksStatus, maxTaskCount, nullptr);
+// g++ emits a spurious warning (and thus error because we compile with -Werror)
+// due to the way std::sort is implemented
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
std::sort(tasksStatus, tasksStatus + nb, sortById);
+#pragma GCC diagnostic pop
for (uint8_t i = 0; i < nb && i < maxTaskCount; i++) {
- char buffer[7] = {0};
+ char buffer[11] = {0};
- sprintf(buffer, "%lu", tasksStatus[i].xTaskNumber);
+ snprintf(buffer, sizeof(buffer), "%lu", tasksStatus[i].xTaskNumber);
lv_table_set_cell_value(infoTask, i + 1, 0, buffer);
switch (tasksStatus[i].eCurrentState) {
case eReady:
@@ -260,9 +274,9 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
lv_table_set_cell_value(infoTask, i + 1, 1, buffer);
lv_table_set_cell_value(infoTask, i + 1, 2, tasksStatus[i].pcTaskName);
if (tasksStatus[i].usStackHighWaterMark < 20) {
- sprintf(buffer, "%d low", tasksStatus[i].usStackHighWaterMark);
+ snprintf(buffer, sizeof(buffer), "%" PRIu16 " low", tasksStatus[i].usStackHighWaterMark);
} else {
- sprintf(buffer, "%d", tasksStatus[i].usStackHighWaterMark);
+ snprintf(buffer, sizeof(buffer), "%" PRIu16, tasksStatus[i].usStackHighWaterMark);
}
lv_table_set_cell_value(infoTask, i + 1, 3, buffer);
}
diff --git a/src/displayapp/screens/SystemInfo.h b/src/displayapp/screens/SystemInfo.h
index 199af51e..301662dc 100644
--- a/src/displayapp/screens/SystemInfo.h
+++ b/src/displayapp/screens/SystemInfo.h
@@ -29,12 +29,12 @@ namespace Pinetime {
const Pinetime::Controllers::Ble& bleController,
const Pinetime::Drivers::Watchdog& watchdog,
Pinetime::Controllers::MotionController& motionController,
- const Pinetime::Drivers::Cst816S& touchPanel);
+ const Pinetime::Drivers::Cst816S& touchPanel,
+ const Pinetime::Drivers::SpiNorFlash& spiNorFlash);
~SystemInfo() override;
bool OnTouchEvent(TouchEvents event) override;
private:
- DisplayApp* app;
Pinetime::Controllers::DateTime& dateTimeController;
const Pinetime::Controllers::Battery& batteryController;
Pinetime::Controllers::BrightnessController& brightnessController;
@@ -42,6 +42,7 @@ namespace Pinetime {
const Pinetime::Drivers::Watchdog& watchdog;
Pinetime::Controllers::MotionController& motionController;
const Pinetime::Drivers::Cst816S& touchPanel;
+ const Pinetime::Drivers::SpiNorFlash& spiNorFlash;
ScreenList<5> screens;
diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp
index 1266f379..7c585a4b 100644
--- a/src/displayapp/screens/Tile.cpp
+++ b/src/displayapp/screens/Tile.cpp
@@ -1,5 +1,4 @@
#include "displayapp/screens/Tile.h"
-#include "displayapp/DisplayApp.h"
#include "displayapp/screens/BatteryIcon.h"
#include "components/ble/BleController.h"
#include "displayapp/InfiniTimeTheme.h"
@@ -30,9 +29,13 @@ Tile::Tile(uint8_t screenID,
Controllers::Settings& settingsController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController,
Controllers::DateTime& dateTimeController,
std::array<Applications, 6>& applications)
- : app {app}, dateTimeController {dateTimeController}, pageIndicator(screenID, numScreens), statusIcons(batteryController, bleController) {
+ : app {app},
+ dateTimeController {dateTimeController},
+ pageIndicator(screenID, numScreens),
+ statusIcons(batteryController, bleController, alarmController) {
settingsController.SetAppMenu(screenID);
@@ -76,7 +79,7 @@ Tile::Tile(uint8_t screenID,
for (uint8_t i = 0; i < 6; i++) {
lv_btnmatrix_set_btn_ctrl(btnm1, i, LV_BTNMATRIX_CTRL_CLICK_TRIG);
- if (applications[i].application == Apps::None) {
+ if (applications[i].application == Apps::None || !applications[i].enabled) {
lv_btnmatrix_set_btn_ctrl(btnm1, i, LV_BTNMATRIX_CTRL_DISABLED);
}
}
diff --git a/src/displayapp/screens/Tile.h b/src/displayapp/screens/Tile.h
index 91acb26c..c16151d0 100644
--- a/src/displayapp/screens/Tile.h
+++ b/src/displayapp/screens/Tile.h
@@ -4,7 +4,7 @@
#include <cstdint>
#include <memory>
#include "displayapp/screens/Screen.h"
-#include "displayapp/Apps.h"
+#include "displayapp/apps/Apps.h"
#include "components/datetime/DateTimeController.h"
#include "components/settings/Settings.h"
#include "components/battery/BatteryController.h"
@@ -19,6 +19,7 @@ namespace Pinetime {
struct Applications {
const char* icon;
Pinetime::Applications::Apps application;
+ bool enabled;
};
explicit Tile(uint8_t screenID,
@@ -27,6 +28,7 @@ namespace Pinetime {
Controllers::Settings& settingsController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController,
Controllers::DateTime& dateTimeController,
std::array<Applications, 6>& applications);
diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp
index df78a5a0..31cde733 100644
--- a/src/displayapp/screens/Timer.cpp
+++ b/src/displayapp/screens/Timer.cpp
@@ -17,7 +17,7 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
}
}
-Timer::Timer(Controllers::TimerController& timerController) : timerController {timerController} {
+Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
@@ -59,10 +59,10 @@ Timer::Timer(Controllers::TimerController& timerController) : timerController {t
lv_obj_set_event_cb(btnPlayPause, btnEventHandler);
lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50);
- txtPlayPause = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);
+ // Create the label as a child of the button so it stays centered by default
+ txtPlayPause = lv_label_create(btnPlayPause, nullptr);
- if (timerController.IsRunning()) {
+ if (timer.IsRunning()) {
SetTimerRunning();
} else {
SetTimerStopped();
@@ -85,7 +85,7 @@ void Timer::MaskReset() {
buttonPressing = false;
// A click event is processed before a release event,
// so the release event would override the "Pause" text without this check
- if (!timerController.IsRunning()) {
+ if (!timer.IsRunning()) {
lv_label_set_text_static(txtPlayPause, "Start");
}
maskPosition = 0;
@@ -103,10 +103,8 @@ void Timer::UpdateMask() {
}
void Timer::Refresh() {
- if (timerController.IsRunning()) {
- auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timerController.GetTimeRemaining());
- minuteCounter.SetValue(secondsRemaining.count() / 60);
- secondCounter.SetValue(secondsRemaining.count() % 60);
+ if (timer.IsRunning()) {
+ DisplayTime();
} else if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
lv_label_set_text_static(txtPlayPause, "Reset");
maskPosition += 15;
@@ -119,6 +117,14 @@ void Timer::Refresh() {
}
}
+void Timer::DisplayTime() {
+ displaySeconds = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
+ if (displaySeconds.IsUpdated()) {
+ minuteCounter.SetValue(displaySeconds.Get().count() / 60);
+ secondCounter.SetValue(displaySeconds.Get().count() % 60);
+ }
+}
+
void Timer::SetTimerRunning() {
minuteCounter.HideControls();
secondCounter.HideControls();
@@ -132,22 +138,19 @@ void Timer::SetTimerStopped() {
}
void Timer::ToggleRunning() {
- if (timerController.IsRunning()) {
- auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timerController.GetTimeRemaining());
- minuteCounter.SetValue(secondsRemaining.count() / 60);
- secondCounter.SetValue(secondsRemaining.count() % 60);
- timerController.StopTimer();
+ if (timer.IsRunning()) {
+ DisplayTime();
+ timer.StopTimer();
SetTimerStopped();
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
auto timerDuration = std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue());
- timerController.StartTimer(timerDuration);
+ timer.StartTimer(timerDuration);
Refresh();
SetTimerRunning();
}
}
void Timer::Reset() {
- minuteCounter.SetValue(0);
- secondCounter.SetValue(0);
+ DisplayTime();
SetTimerStopped();
}
diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h
index a6e26063..a07c729b 100644
--- a/src/displayapp/screens/Timer.h
+++ b/src/displayapp/screens/Timer.h
@@ -1,45 +1,60 @@
#pragma once
#include "displayapp/screens/Screen.h"
-#include "components/datetime/DateTimeController.h"
#include "systemtask/SystemTask.h"
#include "displayapp/LittleVgl.h"
#include "displayapp/widgets/Counter.h"
+#include "utility/DirtyValue.h"
#include <lvgl/lvgl.h>
-#include "components/timer/TimerController.h"
+#include "components/timer/Timer.h"
+#include "Symbols.h"
-namespace Pinetime::Applications::Screens {
- class Timer : public Screen {
- public:
- Timer(Controllers::TimerController& timerController);
- ~Timer() override;
- void Refresh() override;
- void Reset();
- void ToggleRunning();
- void ButtonPressed();
- void MaskReset();
+namespace Pinetime::Applications {
+ namespace Screens {
+ class Timer : public Screen {
+ public:
+ Timer(Controllers::Timer& timerController);
+ ~Timer() override;
+ void Refresh() override;
+ void Reset();
+ void ToggleRunning();
+ void ButtonPressed();
+ void MaskReset();
- private:
- void SetTimerRunning();
- void SetTimerStopped();
- void UpdateMask();
- Controllers::TimerController& timerController;
+ private:
+ void SetTimerRunning();
+ void SetTimerStopped();
+ void UpdateMask();
+ void DisplayTime();
+ Pinetime::Controllers::Timer& timer;
- lv_obj_t* btnPlayPause;
- lv_obj_t* txtPlayPause;
+ lv_obj_t* btnPlayPause;
+ lv_obj_t* txtPlayPause;
- lv_obj_t* btnObjectMask;
- lv_obj_t* highlightObjectMask;
- lv_objmask_mask_t* btnMask;
- lv_objmask_mask_t* highlightMask;
+ lv_obj_t* btnObjectMask;
+ lv_obj_t* highlightObjectMask;
+ lv_objmask_mask_t* btnMask;
+ lv_objmask_mask_t* highlightMask;
- lv_task_t* taskRefresh;
- Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
- Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
+ lv_task_t* taskRefresh;
+ Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
+ Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
- bool buttonPressing = false;
- lv_coord_t maskPosition = 0;
- TickType_t pressTime = 0;
+ bool buttonPressing = false;
+ lv_coord_t maskPosition = 0;
+ TickType_t pressTime = 0;
+ Utility::DirtyValue<std::chrono::seconds> displaySeconds;
+ };
+ }
+
+ template <>
+ struct AppTraits<Apps::Timer> {
+ static constexpr Apps app = Apps::Timer;
+ static constexpr const char* icon = Screens::Symbols::hourGlass;
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Timer(controllers.timer);
+ };
};
}
diff --git a/src/displayapp/screens/Twos.cpp b/src/displayapp/screens/Twos.cpp
index 8157a160..6f2eff40 100644
--- a/src/displayapp/screens/Twos.cpp
+++ b/src/displayapp/screens/Twos.cpp
@@ -242,7 +242,7 @@ void Twos::updateGridDisplay() {
const unsigned int col = i % nCols;
if (grid[row][col].value > 0) {
char buffer[7];
- sprintf(buffer, "%d", grid[row][col].value);
+ snprintf(buffer, sizeof(buffer), "%u", grid[row][col].value);
lv_table_set_cell_value(gridDisplay, row, col, buffer);
} else {
lv_table_set_cell_value(gridDisplay, row, col, "");
diff --git a/src/displayapp/screens/Twos.h b/src/displayapp/screens/Twos.h
index e731eae6..52449fd3 100644
--- a/src/displayapp/screens/Twos.h
+++ b/src/displayapp/screens/Twos.h
@@ -1,7 +1,8 @@
#pragma once
-#include <lvgl/src/lv_core/lv_obj.h>
+#include "displayapp/apps/Apps.h"
#include "displayapp/screens/Screen.h"
+#include "displayapp/Controllers.h"
namespace Pinetime {
namespace Applications {
@@ -35,5 +36,15 @@ namespace Pinetime {
bool placeNewTile();
};
}
+
+ template <>
+ struct AppTraits<Apps::Twos> {
+ static constexpr Apps app = Apps::Twos;
+ static constexpr const char* icon = "2";
+
+ static Screens::Screen* Create(AppControllers& /*controllers*/) {
+ return new Screens::Twos();
+ };
+ };
}
}
diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp
index 76d01cf1..80a1c8b9 100644
--- a/src/displayapp/screens/WatchFaceAnalog.cpp
+++ b/src/displayapp/screens/WatchFaceAnalog.cpp
@@ -8,8 +8,6 @@
#include "components/settings/Settings.h"
#include "displayapp/InfiniTimeTheme.h"
-LV_IMG_DECLARE(bg_clock);
-
using namespace Pinetime::Applications::Screens;
namespace {
@@ -60,9 +58,41 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
sMinute = 99;
sSecond = 99;
- lv_obj_t* bg_clock_img = lv_img_create(lv_scr_act(), nullptr);
- lv_img_set_src(bg_clock_img, &bg_clock);
- lv_obj_align(bg_clock_img, nullptr, LV_ALIGN_CENTER, 0, 0);
+ minor_scales = lv_linemeter_create(lv_scr_act(), nullptr);
+ lv_linemeter_set_scale(minor_scales, 300, 51);
+ lv_linemeter_set_angle_offset(minor_scales, 180);
+ lv_obj_set_size(minor_scales, 240, 240);
+ lv_obj_align(minor_scales, nullptr, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_bg_opa(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
+ lv_obj_set_style_local_scale_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4);
+ lv_obj_set_style_local_scale_end_line_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1);
+ lv_obj_set_style_local_scale_end_color(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
+
+ major_scales = lv_linemeter_create(lv_scr_act(), nullptr);
+ lv_linemeter_set_scale(major_scales, 300, 11);
+ lv_linemeter_set_angle_offset(major_scales, 180);
+ lv_obj_set_size(major_scales, 240, 240);
+ lv_obj_align(major_scales, nullptr, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
+ lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 6);
+ lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4);
+ lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+
+ large_scales = lv_linemeter_create(lv_scr_act(), nullptr);
+ lv_linemeter_set_scale(large_scales, 180, 3);
+ lv_linemeter_set_angle_offset(large_scales, 180);
+ lv_obj_set_size(large_scales, 240, 240);
+ lv_obj_align(large_scales, nullptr, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_style_local_bg_opa(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
+ lv_obj_set_style_local_scale_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 20);
+ lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4);
+ lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
+
+ twelve = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER);
+ lv_label_set_text_static(twelve, "12");
+ lv_obj_set_pos(twelve, 110, 10);
+ lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
batteryIcon.Create(lv_scr_act());
lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
@@ -226,7 +256,7 @@ void WatchFaceAnalog::Refresh() {
if (currentDateTime.IsUpdated()) {
UpdateClock();
- currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
+ currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
}
diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h
index b32293da..958ff64d 100644
--- a/src/displayapp/screens/WatchFaceAnalog.h
+++ b/src/displayapp/screens/WatchFaceAnalog.h
@@ -9,7 +9,8 @@
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
-#include <displayapp/screens/BatteryIcon.h>
+#include "displayapp/screens/BatteryIcon.h"
+#include "utility/DirtyValue.h"
namespace Pinetime {
namespace Controllers {
@@ -37,13 +38,17 @@ namespace Pinetime {
private:
uint8_t sHour, sMinute, sSecond;
- DirtyValue<uint8_t> batteryPercentRemaining {0};
- DirtyValue<bool> isCharging {};
- DirtyValue<bool> bleState {};
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
- DirtyValue<bool> notificationState {false};
- using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
+ Utility::DirtyValue<uint8_t> batteryPercentRemaining {0};
+ Utility::DirtyValue<bool> isCharging {};
+ Utility::DirtyValue<bool> bleState {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
+ Utility::DirtyValue<bool> notificationState {false};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
+
+ lv_obj_t* minor_scales;
+ lv_obj_t* major_scales;
+ lv_obj_t* large_scales;
+ lv_obj_t* twelve;
lv_obj_t* hour_body;
lv_obj_t* hour_body_trace;
@@ -70,7 +75,7 @@ namespace Pinetime {
BatteryIcon batteryIcon;
- const Controllers::DateTime& dateTimeController;
+ Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::NotificationManager& notificationManager;
@@ -82,5 +87,23 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct WatchFaceTraits<WatchFace::Analog> {
+ static constexpr WatchFace watchFace = WatchFace::Analog;
+ static constexpr const char* name = "Analog face";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::WatchFaceAnalog(controllers.dateTimeController,
+ controllers.batteryController,
+ controllers.bleController,
+ controllers.notificationManager,
+ controllers.settingsController);
+ };
+
+ static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
+ return true;
+ }
+ };
}
}
diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp
index ca37c8fc..c695f852 100644
--- a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp
+++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp
@@ -48,14 +48,14 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi
font_segment115 = lv_font_load("F:/fonts/7segments_115.bin");
}
- label_battery_vallue = lv_label_create(lv_scr_act(), nullptr);
- lv_obj_align(label_battery_vallue, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
- lv_obj_set_style_local_text_color(label_battery_vallue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
- lv_label_set_text_static(label_battery_vallue, "00%");
+ label_battery_value = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_align(label_battery_value, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
+ lv_obj_set_style_local_text_color(label_battery_value, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
+ lv_label_set_text_static(label_battery_value, "00%");
batteryIcon.Create(lv_scr_act());
batteryIcon.SetColor(color_text);
- lv_obj_align(batteryIcon.GetObject(), label_battery_vallue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
+ lv_obj_align(batteryIcon.GetObject(), label_battery_value, LV_ALIGN_OUT_LEFT_MID, -5, 0);
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
@@ -203,7 +203,7 @@ void WatchFaceCasioStyleG7710::Refresh() {
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
batteryIcon.SetBatteryPercentage(batteryPercent);
- lv_label_set_text_fmt(label_battery_vallue, "%d%%", batteryPercent);
+ lv_label_set_text_fmt(label_battery_value, "%d%%", batteryPercent);
}
bleState = bleController.IsConnected();
@@ -211,7 +211,7 @@ void WatchFaceCasioStyleG7710::Refresh() {
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
}
- lv_obj_realign(label_battery_vallue);
+ lv_obj_realign(label_battery_value);
lv_obj_realign(batteryIcon.GetObject());
lv_obj_realign(batteryPlug);
lv_obj_realign(bleIcon);
@@ -222,43 +222,36 @@ void WatchFaceCasioStyleG7710::Refresh() {
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
}
- currentDateTime = dateTimeController.CurrentDateTime();
-
+ currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
- auto hour = dateTimeController.Hours();
- auto minute = dateTimeController.Minutes();
- auto year = dateTimeController.Year();
- auto month = dateTimeController.Month();
- auto dayOfWeek = dateTimeController.DayOfWeek();
- auto day = dateTimeController.Day();
- auto dayOfYear = dateTimeController.DayOfYear();
-
- auto weekNumberFormat = "%V";
+ uint8_t hour = dateTimeController.Hours();
+ uint8_t minute = dateTimeController.Minutes();
- if (displayedHour != hour || displayedMinute != minute) {
- displayedHour = hour;
- displayedMinute = minute;
-
- if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
- char ampmChar[2] = "A";
- 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(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_CENTER, 0, 40);
- } else {
- lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute);
- lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
+ if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
+ char ampmChar[2] = "A";
+ 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(label_time_ampm, ampmChar);
+ lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute);
+ } else {
+ lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute);
}
+ lv_obj_realign(label_time);
+
+ currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get());
+ if (currentDate.IsUpdated()) {
+ const char* weekNumberFormat = "%V";
- if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
+ uint16_t year = dateTimeController.Year();
+ Controllers::DateTime::Months month = dateTimeController.Month();
+ uint8_t day = dateTimeController.Day();
+ int dayOfYear = dateTimeController.DayOfYear();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
// 24h mode: ddmmyyyy, first DOW=Monday;
lv_label_set_text_fmt(label_date, "%3d-%2d", day, month);
@@ -293,11 +286,6 @@ void WatchFaceCasioStyleG7710::Refresh() {
lv_obj_realign(label_day_of_year);
lv_obj_realign(label_week_number);
lv_obj_realign(label_date);
-
- currentYear = year;
- currentMonth = month;
- currentDayOfWeek = dayOfWeek;
- currentDay = day;
}
}
@@ -317,8 +305,7 @@ void WatchFaceCasioStyleG7710::Refresh() {
}
stepCount = motionController.NbSteps();
- motionSensorOk = motionController.IsSensorOk();
- if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
+ if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_realign(stepValue);
lv_obj_realign(stepIcon);
diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.h b/src/displayapp/screens/WatchFaceCasioStyleG7710.h
index 0445c9f2..0f46a692 100644
--- a/src/displayapp/screens/WatchFaceCasioStyleG7710.h
+++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.h
@@ -5,9 +5,12 @@
#include <chrono>
#include <cstdint>
#include <memory>
+#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/BleController.h"
+#include "utility/DirtyValue.h"
+#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
@@ -39,24 +42,16 @@ namespace Pinetime {
static bool IsAvailable(Pinetime::Controllers::FS& filesystem);
private:
- uint8_t displayedHour = -1;
- uint8_t displayedMinute = -1;
-
- uint16_t currentYear = 1970;
- Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
- Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
- uint8_t currentDay = 0;
-
- DirtyValue<uint8_t> batteryPercentRemaining {};
- DirtyValue<bool> powerPresent {};
- DirtyValue<bool> bleState {};
- DirtyValue<bool> bleRadioEnabled {};
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
- DirtyValue<bool> motionSensorOk {};
- DirtyValue<uint32_t> stepCount {};
- DirtyValue<uint8_t> heartbeat {};
- DirtyValue<bool> heartbeatRunning {};
- DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
+ Utility::DirtyValue<bool> powerPresent {};
+ Utility::DirtyValue<bool> bleState {};
+ Utility::DirtyValue<bool> bleRadioEnabled {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
+ Utility::DirtyValue<uint32_t> stepCount {};
+ Utility::DirtyValue<uint8_t> heartbeat {};
+ Utility::DirtyValue<bool> heartbeatRunning {};
+ Utility::DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
lv_point_t line_icons_points[3] {{0, 5}, {117, 5}, {122, 0}};
lv_point_t line_day_of_week_number_points[4] {{0, 0}, {100, 0}, {95, 95}, {0, 95}};
@@ -82,7 +77,7 @@ namespace Pinetime {
lv_obj_t* backgroundLabel;
lv_obj_t* bleIcon;
lv_obj_t* batteryPlug;
- lv_obj_t* label_battery_vallue;
+ lv_obj_t* label_battery_value;
lv_obj_t* heartbeatIcon;
lv_obj_t* heartbeatValue;
lv_obj_t* stepIcon;
@@ -106,5 +101,26 @@ namespace Pinetime {
lv_font_t* font_segment115 = nullptr;
};
}
+
+ template <>
+ struct WatchFaceTraits<WatchFace::CasioStyleG7710> {
+ static constexpr WatchFace watchFace = WatchFace::CasioStyleG7710;
+ static constexpr const char* name = "Casio G7710";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::WatchFaceCasioStyleG7710(controllers.dateTimeController,
+ controllers.batteryController,
+ controllers.bleController,
+ controllers.notificationManager,
+ controllers.settingsController,
+ controllers.heartRateController,
+ controllers.motionController,
+ controllers.filesystem);
+ };
+
+ static bool IsAvailable(Pinetime::Controllers::FS& filesystem) {
+ return Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem);
+ }
+ };
}
}
diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp
index ad35b5c9..3163c6e7 100644
--- a/src/displayapp/screens/WatchFaceDigital.cpp
+++ b/src/displayapp/screens/WatchFaceDigital.cpp
@@ -2,13 +2,16 @@
#include <lvgl/lvgl.h>
#include <cstdio>
+
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
+#include "displayapp/screens/WeatherSymbols.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/ble/SimpleWeatherService.h"
#include "components/settings/Settings.h"
using namespace Pinetime::Applications::Screens;
@@ -16,17 +19,20 @@ using namespace Pinetime::Applications::Screens;
WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
- Controllers::MotionController& motionController)
+ Controllers::MotionController& motionController,
+ Controllers::SimpleWeatherService& weatherService)
: currentDateTime {{}},
dateTimeController {dateTimeController},
notificationManager {notificationManager},
settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController},
- statusIcons(batteryController, bleController) {
+ weatherService {weatherService},
+ statusIcons(batteryController, bleController, alarmController) {
statusIcons.Create();
@@ -35,6 +41,18 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
+ weatherIcon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
+ lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons);
+ lv_label_set_text(weatherIcon, "");
+ lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 50);
+ lv_obj_set_auto_realign(weatherIcon, true);
+
+ temperature = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
+ lv_label_set_text(temperature, "");
+ lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50);
+
label_date = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
@@ -85,40 +103,34 @@ void WatchFaceDigital::Refresh() {
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
}
- currentDateTime = dateTimeController.CurrentDateTime();
+ currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
- auto hour = dateTimeController.Hours();
- auto minute = dateTimeController.Minutes();
- auto year = dateTimeController.Year();
- auto month = dateTimeController.Month();
- auto dayOfWeek = dateTimeController.DayOfWeek();
- auto day = dateTimeController.Day();
+ uint8_t hour = dateTimeController.Hours();
+ uint8_t minute = dateTimeController.Minutes();
- if (displayedHour != hour || displayedMinute != minute) {
- displayedHour = hour;
- displayedMinute = minute;
-
- 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(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 (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(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)) {
+ currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get());
+ if (currentDate.IsUpdated()) {
+ uint16_t year = dateTimeController.Year();
+ uint8_t day = dateTimeController.Day();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
lv_label_set_text_fmt(label_date,
"%s %d %s %d",
@@ -135,11 +147,6 @@ void WatchFaceDigital::Refresh() {
year);
}
lv_obj_realign(label_date);
-
- currentYear = year;
- currentMonth = month;
- currentDayOfWeek = dayOfWeek;
- currentDay = day;
}
}
@@ -159,10 +166,29 @@ void WatchFaceDigital::Refresh() {
}
stepCount = motionController.NbSteps();
- motionSensorOk = motionController.IsSensorOk();
- if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
+ if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_realign(stepValue);
lv_obj_realign(stepIcon);
}
+
+ currentWeather = weatherService.Current();
+ if (currentWeather.IsUpdated()) {
+ auto optCurrentWeather = currentWeather.Get();
+ if (optCurrentWeather) {
+ int16_t temp = optCurrentWeather->temperature.Celsius();
+ char tempUnit = 'C';
+ if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
+ temp = optCurrentWeather->temperature.Fahrenheit();
+ tempUnit = 'F';
+ }
+ lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
+ lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
+ } else {
+ lv_label_set_text_static(temperature, "");
+ lv_label_set_text(weatherIcon, "");
+ }
+ lv_obj_realign(temperature);
+ lv_obj_realign(weatherIcon);
+ }
}
diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h
index 0931f007..3005cea5 100644
--- a/src/displayapp/screens/WatchFaceDigital.h
+++ b/src/displayapp/screens/WatchFaceDigital.h
@@ -6,14 +6,18 @@
#include <memory>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
+#include "components/ble/SimpleWeatherService.h"
#include "components/ble/BleController.h"
#include "displayapp/widgets/StatusIcons.h"
+#include "utility/DirtyValue.h"
+#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class Ble;
+ class AlarmController;
class NotificationManager;
class HeartRateController;
class MotionController;
@@ -27,10 +31,12 @@ namespace Pinetime {
WatchFaceDigital(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
- Controllers::MotionController& motionController);
+ Controllers::MotionController& motionController,
+ Controllers::SimpleWeatherService& weather);
~WatchFaceDigital() override;
void Refresh() override;
@@ -39,21 +45,14 @@ namespace Pinetime {
uint8_t displayedHour = -1;
uint8_t displayedMinute = -1;
- uint16_t currentYear = 1970;
- Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
- Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
- uint8_t currentDay = 0;
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
+ Utility::DirtyValue<uint32_t> stepCount {};
+ Utility::DirtyValue<uint8_t> heartbeat {};
+ Utility::DirtyValue<bool> heartbeatRunning {};
+ Utility::DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<std::optional<Pinetime::Controllers::SimpleWeatherService::CurrentWeather>> currentWeather {};
- DirtyValue<uint8_t> batteryPercentRemaining {};
- DirtyValue<bool> powerPresent {};
- DirtyValue<bool> bleState {};
- DirtyValue<bool> bleRadioEnabled {};
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
- DirtyValue<bool> motionSensorOk {};
- DirtyValue<uint32_t> stepCount {};
- DirtyValue<uint8_t> heartbeat {};
- DirtyValue<bool> heartbeatRunning {};
- DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
lv_obj_t* label_time;
lv_obj_t* label_time_ampm;
@@ -63,16 +62,41 @@ namespace Pinetime {
lv_obj_t* stepIcon;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
+ lv_obj_t* weatherIcon;
+ lv_obj_t* temperature;
Controllers::DateTime& dateTimeController;
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
+ Controllers::SimpleWeatherService& weatherService;
lv_task_t* taskRefresh;
Widgets::StatusIcons statusIcons;
};
}
+
+ template <>
+ struct WatchFaceTraits<WatchFace::Digital> {
+ static constexpr WatchFace watchFace = WatchFace::Digital;
+ static constexpr const char* name = "Digital face";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::WatchFaceDigital(controllers.dateTimeController,
+ controllers.batteryController,
+ controllers.bleController,
+ controllers.alarmController,
+ controllers.notificationManager,
+ controllers.settingsController,
+ controllers.heartRateController,
+ controllers.motionController,
+ *controllers.weatherController);
+ };
+
+ static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
+ return true;
+ }
+ };
}
}
diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp
index ab0898e0..40f2abbb 100644
--- a/src/displayapp/screens/WatchFaceInfineat.cpp
+++ b/src/displayapp/screens/WatchFaceInfineat.cpp
@@ -397,74 +397,52 @@ void WatchFaceInfineat::Refresh() {
lv_obj_align(notificationIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
}
- currentDateTime = dateTimeController.CurrentDateTime();
-
+ currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
- auto hour = dateTimeController.Hours();
- auto minute = dateTimeController.Minutes();
- auto year = dateTimeController.Year();
- auto month = dateTimeController.Month();
- auto dayOfWeek = dateTimeController.DayOfWeek();
- auto day = dateTimeController.Day();
-
- char minutesChar[3];
- sprintf(minutesChar, "%02d", static_cast<int>(minute));
-
- char hoursChar[3];
- char ampmChar[3];
+ uint8_t hour = dateTimeController.Hours();
+ uint8_t minute = dateTimeController.Minutes();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
- if (hour < 12) {
- if (hour == 0) {
- hour = 12;
- }
- sprintf(ampmChar, "AM");
- } else { // hour >= 12
- if (hour != 12) {
- hour = hour - 12;
- }
- sprintf(ampmChar, "PM");
+ 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(labelTimeAmPm, ampmChar);
}
- sprintf(hoursChar, "%02d", hour);
-
- if ((hoursChar[0] != displayedChar[0]) || (hoursChar[1] != displayedChar[1]) || (minutesChar[0] != displayedChar[2]) ||
- (minutesChar[1] != displayedChar[3])) {
- displayedChar[0] = hoursChar[0];
- displayedChar[1] = hoursChar[1];
- displayedChar[2] = minutesChar[0];
- displayedChar[3] = minutesChar[1];
-
- lv_label_set_text_fmt(labelHour, "%s", hoursChar);
- lv_label_set_text_fmt(labelMinutes, "%s", minutesChar);
- }
+ lv_label_set_text_fmt(labelHour, "%02d", hour);
+ lv_label_set_text_fmt(labelMinutes, "%02d", minute);
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
- lv_label_set_text(labelTimeAmPm, ampmChar);
lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 10);
lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 5);
lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
}
- if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
- lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(), day);
+ currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get());
+ if (currentDate.IsUpdated()) {
+ uint8_t day = dateTimeController.Day();
+ Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek();
+ lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(dayOfWeek), day);
lv_obj_realign(labelDate);
-
- currentYear = year;
- currentMonth = month;
- currentDayOfWeek = dayOfWeek;
- currentDay = day;
}
}
batteryPercentRemaining = batteryController.PercentRemaining();
isCharging = batteryController.IsCharging();
- if (batteryController.IsCharging()) { // Charging battery animation
- chargingBatteryPercent += 1;
+ // Charging battery animation
+ if (batteryController.IsCharging() && (xTaskGetTickCount() - chargingAnimationTick > pdMS_TO_TICKS(150))) {
+ // Dividing 100 by the height gives the battery percentage required to shift the animation by 1 pixel
+ chargingBatteryPercent += 100 / lv_obj_get_height(logoPine);
if (chargingBatteryPercent > 100) {
chargingBatteryPercent = batteryPercentRemaining.Get();
}
SetBatteryLevel(chargingBatteryPercent);
+ chargingAnimationTick = xTaskGetTickCount();
} else if (isCharging.IsUpdated() || batteryPercentRemaining.IsUpdated()) {
chargingBatteryPercent = batteryPercentRemaining.Get();
SetBatteryLevel(chargingBatteryPercent);
@@ -478,8 +456,7 @@ void WatchFaceInfineat::Refresh() {
}
stepCount = motionController.NbSteps();
- motionSensorOk = motionController.IsSensorOk();
- if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
+ if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 10, 0);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
diff --git a/src/displayapp/screens/WatchFaceInfineat.h b/src/displayapp/screens/WatchFaceInfineat.h
index 26973efe..78d020f1 100644
--- a/src/displayapp/screens/WatchFaceInfineat.h
+++ b/src/displayapp/screens/WatchFaceInfineat.h
@@ -4,8 +4,11 @@
#include <chrono>
#include <cstdint>
#include <memory>
+#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
+#include "utility/DirtyValue.h"
+#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
@@ -42,23 +45,18 @@ namespace Pinetime {
static bool IsAvailable(Pinetime::Controllers::FS& filesystem);
private:
- char displayedChar[5] {};
-
- uint16_t currentYear = 1970;
- Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
- Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
- uint8_t currentDay = 0;
uint32_t savedTick = 0;
uint8_t chargingBatteryPercent = 101; // not a mistake ;)
+ TickType_t chargingAnimationTick = 0;
- DirtyValue<uint8_t> batteryPercentRemaining {};
- DirtyValue<bool> isCharging {};
- DirtyValue<bool> bleState {};
- DirtyValue<bool> bleRadioEnabled {};
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
- DirtyValue<bool> motionSensorOk {};
- DirtyValue<uint32_t> stepCount {};
- DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
+ Utility::DirtyValue<bool> isCharging {};
+ Utility::DirtyValue<bool> bleState {};
+ Utility::DirtyValue<bool> bleRadioEnabled {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
+ Utility::DirtyValue<uint32_t> stepCount {};
+ Utility::DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
// Lines making up the side cover
lv_obj_t* lineBattery;
@@ -102,5 +100,25 @@ namespace Pinetime {
lv_font_t* font_bebas = nullptr;
};
}
+
+ template <>
+ struct WatchFaceTraits<WatchFace::Infineat> {
+ static constexpr WatchFace watchFace = WatchFace::Infineat;
+ static constexpr const char* name = "Infineat face";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::WatchFaceInfineat(controllers.dateTimeController,
+ controllers.batteryController,
+ controllers.bleController,
+ controllers.notificationManager,
+ controllers.settingsController,
+ controllers.motionController,
+ controllers.filesystem);
+ };
+
+ static bool IsAvailable(Pinetime::Controllers::FS& filesystem) {
+ return Screens::WatchFaceInfineat::IsAvailable(filesystem);
+ }
+ };
}
}
diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.cpp b/src/displayapp/screens/WatchFacePineTimeStyle.cpp
index 85505a63..22ccefc7 100644
--- a/src/displayapp/screens/WatchFacePineTimeStyle.cpp
+++ b/src/displayapp/screens/WatchFacePineTimeStyle.cpp
@@ -22,17 +22,19 @@
#include "displayapp/screens/WatchFacePineTimeStyle.h"
#include <lvgl/lvgl.h>
#include <cstdio>
-#include <displayapp/Colors.h>
+#include "displayapp/Colors.h"
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/BleIcon.h"
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
+#include "displayapp/screens/WeatherSymbols.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
#include "displayapp/DisplayApp.h"
+#include "components/ble/SimpleWeatherService.h"
using namespace Pinetime::Applications::Screens;
@@ -48,7 +50,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
- Controllers::MotionController& motionController)
+ Controllers::MotionController& motionController,
+ Controllers::SimpleWeatherService& weatherService)
: currentDateTime {{}},
batteryIcon(false),
dateTimeController {dateTimeController},
@@ -56,7 +59,8 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
bleController {bleController},
notificationManager {notificationManager},
settingsController {settingsController},
- motionController {motionController} {
+ motionController {motionController},
+ weatherService {weatherService} {
// Create a 200px wide background rectangle
timebar = lv_obj_create(lv_scr_act(), nullptr);
@@ -94,27 +98,53 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
// Display icons
batteryIcon.Create(sidebar);
batteryIcon.SetColor(LV_COLOR_BLACK);
- lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_MID, 0, 2);
+ lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_MID, 10, 2);
plugIcon = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(plugIcon, Symbols::plug);
lv_obj_set_style_local_text_color(plugIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
- lv_obj_align(plugIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
+ lv_obj_align(plugIcon, sidebar, LV_ALIGN_IN_TOP_MID, 10, 2);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
- lv_label_set_text_static(bleIcon, "");
+ lv_obj_align(bleIcon, sidebar, LV_ALIGN_IN_TOP_MID, -10, 2);
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_BLACK);
- lv_label_set_text_static(notificationIcon, "");
+ lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Convert(settingsController.GetPTSColorTime()));
+ lv_obj_align(notificationIcon, timebar, LV_ALIGN_IN_TOP_LEFT, 5, 5);
+
+ weatherIcon = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons);
+ lv_label_set_text(weatherIcon, Symbols::ban);
+ lv_obj_align(weatherIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 35);
+ lv_obj_set_auto_realign(weatherIcon, true);
+ if (settingsController.GetPTSWeather() == Pinetime::Controllers::Settings::PTSWeather::On) {
+ lv_obj_set_hidden(weatherIcon, false);
+ } else {
+ lv_obj_set_hidden(weatherIcon, true);
+ }
+
+ temperature = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_label_set_text(temperature, "--");
+ lv_obj_align(temperature, sidebar, LV_ALIGN_IN_TOP_MID, 0, 65);
+ if (settingsController.GetPTSWeather() == Pinetime::Controllers::Settings::PTSWeather::On) {
+ lv_obj_set_hidden(temperature, false);
+ } else {
+ lv_obj_set_hidden(temperature, true);
+ }
// Calendar icon
calendarOuter = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_radius(calendarOuter, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
lv_obj_set_size(calendarOuter, 34, 34);
- lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
+ if (settingsController.GetPTSWeather() == Pinetime::Controllers::Settings::PTSWeather::On) {
+ lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 20);
+ } else {
+ lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
+ }
calendarInner = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(calendarInner, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
@@ -150,17 +180,17 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
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_static(dateDayOfWeek, "THU");
- lv_obj_align(dateDayOfWeek, sidebar, LV_ALIGN_CENTER, 0, -34);
+ lv_obj_align(dateDayOfWeek, calendarOuter, LV_ALIGN_CENTER, 0, -32);
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_static(dateDay, "25");
- lv_obj_align(dateDay, sidebar, LV_ALIGN_CENTER, 0, 3);
+ lv_obj_align(dateDay, calendarOuter, 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_static(dateMonth, "MAR");
- lv_obj_align(dateMonth, sidebar, LV_ALIGN_CENTER, 0, 32);
+ lv_obj_align(dateMonth, calendarOuter, LV_ALIGN_CENTER, 0, 32);
// Step count gauge
if (settingsController.GetPTSColorBar() == Pinetime::Controllers::Settings::Colors::White) {
@@ -323,13 +353,23 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
btnSteps = lv_btn_create(lv_scr_act(), nullptr);
btnSteps->user_data = this;
lv_obj_set_size(btnSteps, 160, 60);
- lv_obj_align(btnSteps, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
+ lv_obj_align(btnSteps, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
lv_obj_set_style_local_bg_opa(btnSteps, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
lv_obj_t* lblSteps = lv_label_create(btnSteps, nullptr);
lv_label_set_text_static(lblSteps, "Steps style");
lv_obj_set_event_cb(btnSteps, event_handler);
lv_obj_set_hidden(btnSteps, true);
+ btnWeather = lv_btn_create(lv_scr_act(), nullptr);
+ btnWeather->user_data = this;
+ lv_obj_set_size(btnWeather, 160, 60);
+ lv_obj_align(btnWeather, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
+ lv_obj_set_style_local_bg_opa(btnWeather, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
+ lv_obj_t* lblWeather = lv_label_create(btnWeather, nullptr);
+ lv_label_set_text_static(lblWeather, "Weather");
+ lv_obj_set_event_cb(btnWeather, event_handler);
+ lv_obj_set_hidden(btnWeather, true);
+
btnSetColor = lv_btn_create(lv_scr_act(), nullptr);
btnSetColor->user_data = this;
lv_obj_set_size(btnSetColor, 150, 60);
@@ -337,9 +377,9 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
lv_obj_set_style_local_radius(btnSetColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
lv_obj_set_style_local_bg_opa(btnSetColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
lv_obj_set_event_cb(btnSetColor, event_handler);
- lbl_btnSetColor = lv_label_create(btnSetColor, nullptr);
- lv_obj_set_style_local_text_font(lbl_btnSetColor, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
- lv_label_set_text_static(lbl_btnSetColor, Symbols::paintbrushLg);
+ lv_obj_t* lblSetColor = lv_label_create(btnSetColor, nullptr);
+ lv_obj_set_style_local_text_font(lblSetColor, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
+ lv_label_set_text_static(lblSetColor, Symbols::paintbrushLg);
lv_obj_set_hidden(btnSetColor, true);
btnSetOpts = lv_btn_create(lv_scr_act(), nullptr);
@@ -349,9 +389,9 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(Controllers::DateTime& dateTimeCo
lv_obj_set_style_local_radius(btnSetOpts, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20);
lv_obj_set_style_local_bg_opa(btnSetOpts, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
lv_obj_set_event_cb(btnSetOpts, event_handler);
- lbl_btnSetOpts = lv_label_create(btnSetOpts, nullptr);
- lv_obj_set_style_local_text_font(lbl_btnSetOpts, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
- lv_label_set_text_static(lbl_btnSetOpts, Symbols::settings);
+ lv_obj_t* lblSetOpts = lv_label_create(btnSetOpts, nullptr);
+ lv_obj_set_style_local_text_font(lblSetOpts, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
+ lv_label_set_text_static(lblSetOpts, Symbols::settings);
lv_obj_set_hidden(btnSetOpts, true);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
@@ -388,6 +428,7 @@ void WatchFacePineTimeStyle::CloseMenu() {
lv_obj_set_hidden(btnRandom, true);
lv_obj_set_hidden(btnClose, true);
lv_obj_set_hidden(btnSteps, true);
+ lv_obj_set_hidden(btnWeather, true);
}
bool WatchFacePineTimeStyle::OnButtonPushed() {
@@ -403,17 +444,6 @@ void WatchFacePineTimeStyle::SetBatteryIcon() {
batteryIcon.SetBatteryPercentage(batteryPercent);
}
-void WatchFacePineTimeStyle::AlignIcons() {
- 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() && !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);
- }
-}
-
void WatchFacePineTimeStyle::Refresh() {
isCharging = batteryController.IsCharging();
if (isCharging.IsUpdated()) {
@@ -437,13 +467,12 @@ void WatchFacePineTimeStyle::Refresh() {
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
- AlignIcons();
+ lv_obj_realign(bleIcon);
}
notificationState = notificationManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
- AlignIcons();
}
currentDateTime = dateTimeController.CurrentDateTime();
@@ -499,8 +528,7 @@ void WatchFacePineTimeStyle::Refresh() {
}
stepCount = motionController.NbSteps();
- motionSensorOk = motionController.IsSensorOk();
- if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
+ if (stepCount.IsUpdated()) {
lv_gauge_set_value(stepGauge, 0, (stepCount.Get() / (settingsController.GetStepsGoal() / 100)) % 100);
lv_obj_realign(stepGauge);
lv_label_set_text_fmt(stepValue, "%luK", (stepCount.Get() / 1000));
@@ -510,6 +538,25 @@ void WatchFacePineTimeStyle::Refresh() {
lv_obj_set_style_local_scale_grad_color(stepGauge, LV_GAUGE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
}
+
+ currentWeather = weatherService.Current();
+ if (currentWeather.IsUpdated()) {
+ auto optCurrentWeather = currentWeather.Get();
+ if (optCurrentWeather) {
+ int16_t temp = optCurrentWeather->temperature.Celsius();
+ if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
+ temp = optCurrentWeather->temperature.Fahrenheit();
+ }
+ lv_label_set_text_fmt(temperature, "%d°", temp);
+ lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
+ } else {
+ lv_label_set_text(temperature, "--");
+ lv_label_set_text(weatherIcon, Symbols::ban);
+ }
+ lv_obj_realign(temperature);
+ lv_obj_realign(weatherIcon);
+ }
+
if (!lv_obj_get_hidden(btnSetColor)) {
if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) {
lv_obj_set_hidden(btnSetColor, true);
@@ -655,6 +702,37 @@ void WatchFacePineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event)
settingsController.SetPTSGaugeStyle(Controllers::Settings::PTSGaugeStyle::Full);
}
}
+ if (object == btnWeather) {
+ if (lv_obj_get_hidden(weatherIcon)) {
+ // show weather icon and temperature
+ lv_obj_set_hidden(weatherIcon, false);
+ lv_obj_set_hidden(temperature, false);
+ lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 20);
+ lv_obj_realign(calendarInner);
+ lv_obj_realign(calendarBar1);
+ lv_obj_realign(calendarBar2);
+ lv_obj_realign(calendarCrossBar1);
+ lv_obj_realign(calendarCrossBar2);
+ lv_obj_realign(dateDayOfWeek);
+ lv_obj_realign(dateDay);
+ lv_obj_realign(dateMonth);
+ settingsController.SetPTSWeather(Controllers::Settings::PTSWeather::On);
+ } else {
+ // hide weather
+ lv_obj_set_hidden(weatherIcon, true);
+ lv_obj_set_hidden(temperature, true);
+ lv_obj_align(calendarOuter, sidebar, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_realign(calendarInner);
+ lv_obj_realign(calendarBar1);
+ lv_obj_realign(calendarBar2);
+ lv_obj_realign(calendarCrossBar1);
+ lv_obj_realign(calendarCrossBar2);
+ lv_obj_realign(dateDayOfWeek);
+ lv_obj_realign(dateDay);
+ lv_obj_realign(dateMonth);
+ settingsController.SetPTSWeather(Controllers::Settings::PTSWeather::Off);
+ }
+ }
if (object == btnSetColor) {
lv_obj_set_hidden(btnSetColor, true);
lv_obj_set_hidden(btnSetOpts, true);
@@ -672,6 +750,7 @@ void WatchFacePineTimeStyle::UpdateSelected(lv_obj_t* object, lv_event_t event)
lv_obj_set_hidden(btnSetColor, true);
lv_obj_set_hidden(btnSetOpts, true);
lv_obj_set_hidden(btnSteps, false);
+ lv_obj_set_hidden(btnWeather, false);
lv_obj_set_hidden(btnClose, false);
}
}
diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.h b/src/displayapp/screens/WatchFacePineTimeStyle.h
index bccb224a..72537095 100644
--- a/src/displayapp/screens/WatchFacePineTimeStyle.h
+++ b/src/displayapp/screens/WatchFacePineTimeStyle.h
@@ -4,11 +4,14 @@
#include <chrono>
#include <cstdint>
#include <memory>
+#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/Colors.h"
#include "components/datetime/DateTimeController.h"
+#include "components/ble/SimpleWeatherService.h"
#include "components/ble/BleController.h"
+#include "utility/DirtyValue.h"
namespace Pinetime {
namespace Controllers {
@@ -29,7 +32,8 @@ namespace Pinetime {
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
- Controllers::MotionController& motionController);
+ Controllers::MotionController& motionController,
+ Controllers::SimpleWeatherService& weather);
~WatchFacePineTimeStyle() override;
bool OnTouchEvent(TouchEvents event) override;
@@ -50,14 +54,14 @@ namespace Pinetime {
uint8_t currentDay = 0;
uint32_t savedTick = 0;
- DirtyValue<uint8_t> batteryPercentRemaining {};
- DirtyValue<bool> isCharging {};
- DirtyValue<bool> bleState {};
- DirtyValue<bool> bleRadioEnabled {};
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
- DirtyValue<bool> motionSensorOk {};
- DirtyValue<uint32_t> stepCount {};
- DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
+ Utility::DirtyValue<bool> isCharging {};
+ Utility::DirtyValue<bool> bleState {};
+ Utility::DirtyValue<bool> bleRadioEnabled {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
+ Utility::DirtyValue<uint32_t> stepCount {};
+ Utility::DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<std::optional<Pinetime::Controllers::SimpleWeatherService::CurrentWeather>> currentWeather {};
static Pinetime::Controllers::Settings::Colors GetNext(Controllers::Settings::Colors color);
static Pinetime::Controllers::Settings::Colors GetPrevious(Controllers::Settings::Colors color);
@@ -72,6 +76,7 @@ namespace Pinetime {
lv_obj_t* btnRandom;
lv_obj_t* btnClose;
lv_obj_t* btnSteps;
+ lv_obj_t* btnWeather;
lv_obj_t* timebar;
lv_obj_t* sidebar;
lv_obj_t* timeDD1;
@@ -81,6 +86,8 @@ namespace Pinetime {
lv_obj_t* dateDayOfWeek;
lv_obj_t* dateDay;
lv_obj_t* dateMonth;
+ lv_obj_t* weatherIcon;
+ lv_obj_t* temperature;
lv_obj_t* plugIcon;
lv_obj_t* bleIcon;
lv_obj_t* calendarOuter;
@@ -93,8 +100,6 @@ namespace Pinetime {
lv_obj_t* stepGauge;
lv_obj_t* btnSetColor;
lv_obj_t* btnSetOpts;
- lv_obj_t* lbl_btnSetColor;
- lv_obj_t* lbl_btnSetOpts;
lv_obj_t* stepIcon;
lv_obj_t* stepValue;
lv_color_t needle_colors[1];
@@ -107,13 +112,33 @@ namespace Pinetime {
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
+ Controllers::SimpleWeatherService& weatherService;
void SetBatteryIcon();
void CloseMenu();
- void AlignIcons();
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct WatchFaceTraits<WatchFace::PineTimeStyle> {
+ static constexpr WatchFace watchFace = WatchFace::PineTimeStyle;
+ static constexpr const char* name = "PineTimeStyle";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::WatchFacePineTimeStyle(controllers.dateTimeController,
+ controllers.batteryController,
+ controllers.bleController,
+ controllers.notificationManager,
+ controllers.settingsController,
+ controllers.motionController,
+ *controllers.weatherController);
+ };
+
+ static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
+ return true;
+ }
+ };
}
}
diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp
index e5ff195e..96d77741 100644
--- a/src/displayapp/screens/WatchFaceTerminal.cpp
+++ b/src/displayapp/screens/WatchFaceTerminal.cpp
@@ -104,45 +104,33 @@ void WatchFaceTerminal::Refresh() {
}
}
- currentDateTime = dateTimeController.CurrentDateTime();
-
+ currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
- auto hour = dateTimeController.Hours();
- auto minute = dateTimeController.Minutes();
- auto second = dateTimeController.Seconds();
- auto year = dateTimeController.Year();
- auto month = dateTimeController.Month();
- auto dayOfWeek = dateTimeController.DayOfWeek();
- auto day = dateTimeController.Day();
-
- if (displayedHour != hour || displayedMinute != minute || displayedSecond != second) {
- displayedHour = hour;
- displayedMinute = minute;
- displayedSecond = second;
+ uint8_t hour = dateTimeController.Hours();
+ uint8_t minute = dateTimeController.Minutes();
+ uint8_t second = dateTimeController.Seconds();
- 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 (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)) {
+ currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get());
+ if (currentDate.IsUpdated()) {
+ uint16_t year = dateTimeController.Year();
+ Controllers::DateTime::Months month = dateTimeController.Month();
+ uint8_t day = dateTimeController.Day();
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;
}
}
@@ -157,8 +145,7 @@ void WatchFaceTerminal::Refresh() {
}
stepCount = motionController.NbSteps();
- motionSensorOk = motionController.IsSensorOk();
- if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
+ if (stepCount.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
index 67156a50..bf460866 100644
--- a/src/displayapp/screens/WatchFaceTerminal.h
+++ b/src/displayapp/screens/WatchFaceTerminal.h
@@ -4,8 +4,10 @@
#include <chrono>
#include <cstdint>
#include <memory>
+#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
+#include "utility/DirtyValue.h"
namespace Pinetime {
namespace Controllers {
@@ -34,25 +36,16 @@ namespace Pinetime {
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<int> batteryPercentRemaining {};
- DirtyValue<bool> powerPresent {};
- DirtyValue<bool> bleState {};
- DirtyValue<bool> bleRadioEnabled {};
- DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime {};
- DirtyValue<bool> motionSensorOk {};
- DirtyValue<uint32_t> stepCount {};
- DirtyValue<uint8_t> heartbeat {};
- DirtyValue<bool> heartbeatRunning {};
- DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<int> batteryPercentRemaining {};
+ Utility::DirtyValue<bool> powerPresent {};
+ Utility::DirtyValue<bool> bleState {};
+ Utility::DirtyValue<bool> bleRadioEnabled {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> currentDateTime {};
+ Utility::DirtyValue<uint32_t> stepCount {};
+ Utility::DirtyValue<uint8_t> heartbeat {};
+ Utility::DirtyValue<bool> heartbeatRunning {};
+ Utility::DirtyValue<bool> notificationState {};
+ Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
lv_obj_t* label_time;
lv_obj_t* label_date;
@@ -75,5 +68,25 @@ namespace Pinetime {
lv_task_t* taskRefresh;
};
}
+
+ template <>
+ struct WatchFaceTraits<WatchFace::Terminal> {
+ static constexpr WatchFace watchFace = WatchFace::Terminal;
+ static constexpr const char* name = "Terminal";
+
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::WatchFaceTerminal(controllers.dateTimeController,
+ controllers.batteryController,
+ controllers.bleController,
+ controllers.notificationManager,
+ controllers.settingsController,
+ controllers.heartRateController,
+ controllers.motionController);
+ };
+
+ static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
+ return true;
+ }
+ };
}
}
diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp
index 4921174c..25464c70 100644
--- a/src/displayapp/screens/Weather.cpp
+++ b/src/displayapp/screens/Weather.cpp
@@ -1,221 +1,197 @@
-/* Copyright (C) 2021 Avamander
+#include "displayapp/screens/Weather.h"
- This file is part of InfiniTime.
-
- InfiniTime is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- InfiniTime is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-#include "Weather.h"
#include <lvgl/lvgl.h>
-#include <components/ble/weather/WeatherService.h>
-#include "Label.h"
-#include "components/battery/BatteryController.h"
-#include "components/ble/BleController.h"
-#include "components/ble/weather/WeatherData.h"
-using namespace Pinetime::Applications::Screens;
+#include "components/ble/SimpleWeatherService.h"
+#include "components/datetime/DateTimeController.h"
+#include "components/settings/Settings.h"
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/WeatherSymbols.h"
+#include "displayapp/InfiniTimeTheme.h"
-Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::WeatherService& weather)
- : app {app},
- weatherService(weather),
- screens {app,
- 0,
- {[this]() -> std::unique_ptr<Screen> {
- return CreateScreenTemperature();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenAir();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenClouds();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenPrecipitation();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenHumidity();
- }},
- Screens::ScreenListModes::UpDown} {
-}
+using namespace Pinetime::Applications::Screens;
-Weather::~Weather() {
- lv_obj_clean(lv_scr_act());
-}
+namespace {
+ lv_color_t TemperatureColor(Pinetime::Controllers::SimpleWeatherService::Temperature temp) {
+ if (temp.Celsius() <= 0) { // freezing
+ return Colors::blue;
+ } else if (temp.Celsius() <= 4) { // ice
+ return LV_COLOR_CYAN;
+ } else if (temp.Celsius() >= 27) { // hot
+ return Colors::deepOrange;
+ }
+ return Colors::orange; // normal
+ }
-void Weather::Refresh() {
- if (running) {
- // screens.Refresh();
+ uint8_t TemperatureStyle(Pinetime::Controllers::SimpleWeatherService::Temperature temp) {
+ if (temp.Celsius() <= 0) { // freezing
+ return LV_TABLE_PART_CELL3;
+ } else if (temp.Celsius() <= 4) { // ice
+ return LV_TABLE_PART_CELL4;
+ } else if (temp.Celsius() >= 27) { // hot
+ return LV_TABLE_PART_CELL6;
+ }
+ return LV_TABLE_PART_CELL5; // normal
}
}
-bool Weather::OnButtonPushed() {
- running = false;
- return true;
-}
+Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService)
+ : settingsController {settingsController}, weatherService {weatherService} {
-bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
- return screens.OnTouchEvent(event);
-}
+ temperature = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_text_font(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+ lv_label_set_text(temperature, "---");
+ lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, 0, -30);
+ lv_obj_set_auto_realign(temperature, true);
-std::unique_ptr<Screen> Weather::CreateScreenTemperature() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::Temperature>& current = weatherService.GetCurrentTemperature();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Temperature#\n\n"
- "#444444 %d#°C \n\n"
- "#444444 %d#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Temperature#\n\n"
- "#444444 %d#°C \n\n"
- "#444444 %hd#\n\n"
- "%llu\n"
- "%lu\n",
- current->temperature / 100,
- current->dewPoint,
- current->timestamp,
- current->expires);
- }
- lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
- return std::unique_ptr<Screen>(new Screens::Label(0, 5, label));
-}
+ minTemperature = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg);
+ lv_label_set_text(minTemperature, "");
+ lv_obj_align(minTemperature, temperature, LV_ALIGN_OUT_LEFT_MID, -10, 0);
+ lv_obj_set_auto_realign(minTemperature, true);
+
+ maxTemperature = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(maxTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg);
+ lv_label_set_text(maxTemperature, "");
+ lv_obj_align(maxTemperature, temperature, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
+ lv_obj_set_auto_realign(maxTemperature, true);
+
+ condition = lv_label_create(lv_scr_act(), nullptr);
+ lv_obj_set_style_local_text_color(condition, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
+ lv_label_set_text(condition, "");
+ lv_obj_align(condition, temperature, LV_ALIGN_OUT_TOP_MID, 0, -10);
+ lv_obj_set_auto_realign(condition, true);
+
+ 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_WHITE);
+ lv_obj_set_style_local_text_font(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons);
+ lv_label_set_text(icon, "");
+ lv_obj_align(icon, condition, LV_ALIGN_OUT_TOP_MID, 0, 0);
+ lv_obj_set_auto_realign(icon, true);
-std::unique_ptr<Screen> Weather::CreateScreenAir() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::AirQuality>& current = weatherService.GetCurrentQuality();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Air quality#\n\n"
- "#444444 %s#\n"
- "#444444 %d#\n\n"
- "%d\n"
- "%d\n",
- "",
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Air quality#\n\n"
- "#444444 %s#\n"
- "#444444 %lu#\n\n"
- "%llu\n"
- "%lu\n",
- current->polluter.c_str(),
- (current->amount / 100),
- current->timestamp,
- current->expires);
+ forecast = lv_table_create(lv_scr_act(), nullptr);
+ lv_table_set_col_cnt(forecast, Controllers::SimpleWeatherService::MaxNbForecastDays);
+ lv_table_set_row_cnt(forecast, 4);
+ // LV_TABLE_PART_CELL1: Default table style
+ lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, Colors::lightGray);
+ // LV_TABLE_PART_CELL2: Condition icon
+ lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_obj_set_style_local_text_font(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, &fontawesome_weathericons);
+ // LV_TABLE_PART_CELL3: Freezing
+ lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, Colors::blue);
+ // LV_TABLE_PART_CELL4: Ice
+ lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_CYAN);
+ // LV_TABLE_PART_CELL5: Normal
+ lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, Colors::orange);
+ // LV_TABLE_PART_CELL6: Hot
+ lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, Colors::deepOrange);
+
+ lv_obj_align(forecast, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
+
+ for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
+ lv_table_set_col_width(forecast, i, 48);
+ lv_table_set_cell_type(forecast, 1, i, LV_TABLE_PART_CELL2);
+ lv_table_set_cell_align(forecast, 0, i, LV_LABEL_ALIGN_CENTER);
+ lv_table_set_cell_align(forecast, 1, i, LV_LABEL_ALIGN_CENTER);
+ lv_table_set_cell_align(forecast, 2, i, LV_LABEL_ALIGN_CENTER);
+ lv_table_set_cell_align(forecast, 3, i, LV_LABEL_ALIGN_CENTER);
}
- lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
- return std::unique_ptr<Screen>(new Screens::Label(0, 5, label));
+
+ taskRefresh = lv_task_create(RefreshTaskCallback, 1000, LV_TASK_PRIO_MID, this);
+ Refresh();
}
-std::unique_ptr<Screen> Weather::CreateScreenClouds() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::Clouds>& current = weatherService.GetCurrentClouds();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Clouds#\n\n"
- "#444444 %d%%#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Clouds#\n\n"
- "#444444 %hhu%%#\n\n"
- "%llu\n"
- "%lu\n",
- current->amount,
- current->timestamp,
- current->expires);
- }
- lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
- return std::unique_ptr<Screen>(new Screens::Label(0, 5, label));
+Weather::~Weather() {
+ lv_task_del(taskRefresh);
+ lv_obj_clean(lv_scr_act());
}
-std::unique_ptr<Screen> Weather::CreateScreenPrecipitation() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::Precipitation>& current = weatherService.GetCurrentPrecipitation();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Precipitation#\n\n"
- "#444444 %d%%#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Precipitation#\n\n"
- "#444444 %hhu%%#\n\n"
- "%llu\n"
- "%lu\n",
- current->amount,
- current->timestamp,
- current->expires);
+void Weather::Refresh() {
+ currentWeather = weatherService.Current();
+ if (currentWeather.IsUpdated()) {
+ auto optCurrentWeather = currentWeather.Get();
+ if (optCurrentWeather) {
+ int16_t temp = optCurrentWeather->temperature.Celsius();
+ int16_t minTemp = optCurrentWeather->minTemperature.Celsius();
+ int16_t maxTemp = optCurrentWeather->maxTemperature.Celsius();
+ char tempUnit = 'C';
+ if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
+ temp = optCurrentWeather->temperature.Fahrenheit();
+ minTemp = optCurrentWeather->minTemperature.Fahrenheit();
+ maxTemp = optCurrentWeather->maxTemperature.Fahrenheit();
+ tempUnit = 'F';
+ }
+ lv_obj_set_style_local_text_color(temperature,
+ LV_LABEL_PART_MAIN,
+ LV_STATE_DEFAULT,
+ TemperatureColor(optCurrentWeather->temperature));
+ lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId));
+ lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId));
+ lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
+ lv_label_set_text_fmt(minTemperature, "%d°", minTemp);
+ lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp);
+ } else {
+ lv_label_set_text(icon, "");
+ lv_label_set_text(condition, "");
+ lv_label_set_text(temperature, "---");
+ lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+ lv_label_set_text(minTemperature, "");
+ lv_label_set_text(maxTemperature, "");
+ }
}
- lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
- return std::unique_ptr<Screen>(new Screens::Label(0, 5, label));
-}
-std::unique_ptr<Screen> Weather::CreateScreenHumidity() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::Humidity>& current = weatherService.GetCurrentHumidity();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Humidity#\n\n"
- "#444444 %d%%#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Humidity#\n\n"
- "#444444 %hhu%%#\n\n"
- "%llu\n"
- "%lu\n",
- current->humidity,
- current->timestamp,
- current->expires);
+ currentForecast = weatherService.GetForecast();
+ if (currentForecast.IsUpdated()) {
+ auto optCurrentForecast = currentForecast.Get();
+ if (optCurrentForecast) {
+ std::tm localTime = *std::localtime(reinterpret_cast<const time_t*>(&optCurrentForecast->timestamp));
+
+ for (int i = 0; i < optCurrentForecast->nbDays; i++) {
+ int16_t maxTemp = optCurrentForecast->days[i]->maxTemperature.Celsius();
+ int16_t minTemp = optCurrentForecast->days[i]->minTemperature.Celsius();
+ if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
+ maxTemp = optCurrentForecast->days[i]->maxTemperature.Fahrenheit();
+ minTemp = optCurrentForecast->days[i]->minTemperature.Fahrenheit();
+ }
+ lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(optCurrentForecast->days[i]->maxTemperature));
+ lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(optCurrentForecast->days[i]->minTemperature));
+ uint8_t wday = localTime.tm_wday + i + 1;
+ if (wday > 7) {
+ wday -= 7;
+ }
+ const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast<Controllers::DateTime::Days>(wday));
+ lv_table_set_cell_value(forecast, 0, i, dayOfWeek);
+ lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i]->iconId));
+ // Pad cells based on the largest number of digits on each column
+ char maxPadding[3] = " ";
+ char minPadding[3] = " ";
+ int diff = snprintf(nullptr, 0, "%d", maxTemp) - snprintf(nullptr, 0, "%d", minTemp);
+ if (diff <= 0) {
+ maxPadding[-diff] = '\0';
+ minPadding[0] = '\0';
+ } else {
+ maxPadding[0] = '\0';
+ minPadding[diff] = '\0';
+ }
+ lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp);
+ lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp);
+ }
+ } else {
+ for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
+ lv_table_set_cell_value(forecast, 0, i, "");
+ lv_table_set_cell_value(forecast, 1, i, "");
+ lv_table_set_cell_value(forecast, 2, i, "");
+ lv_table_set_cell_value(forecast, 3, i, "");
+ lv_table_set_cell_type(forecast, 2, i, LV_TABLE_PART_CELL1);
+ lv_table_set_cell_type(forecast, 3, i, LV_TABLE_PART_CELL1);
+ }
+ }
}
- lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
- lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
- return std::unique_ptr<Screen>(new Screens::Label(0, 5, label));
}
diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h
index 459534aa..6975311e 100644
--- a/src/displayapp/screens/Weather.h
+++ b/src/displayapp/screens/Weather.h
@@ -1,45 +1,56 @@
#pragma once
-#include <memory>
-#include <components/ble/weather/WeatherService.h>
-#include "Screen.h"
-#include "ScreenList.h"
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "displayapp/screens/Screen.h"
+#include "components/ble/SimpleWeatherService.h"
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
+#include "utility/DirtyValue.h"
namespace Pinetime {
- namespace Applications {
- class DisplayApp;
+ namespace Controllers {
+ class Settings;
+ }
+
+ namespace Applications {
namespace Screens {
+
class Weather : public Screen {
public:
- explicit Weather(DisplayApp* app, Pinetime::Controllers::WeatherService& weather);
-
+ Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService);
~Weather() override;
void Refresh() override;
- bool OnButtonPushed() override;
-
- bool OnTouchEvent(TouchEvents event) override;
-
private:
- DisplayApp* app;
- bool running = true;
-
- Controllers::WeatherService& weatherService;
-
- ScreenList<5> screens;
+ Controllers::Settings& settingsController;
+ Controllers::SimpleWeatherService& weatherService;
- std::unique_ptr<Screen> CreateScreenTemperature();
+ Utility::DirtyValue<std::optional<Controllers::SimpleWeatherService::CurrentWeather>> currentWeather {};
+ Utility::DirtyValue<std::optional<Controllers::SimpleWeatherService::Forecast>> currentForecast {};
- std::unique_ptr<Screen> CreateScreenAir();
+ lv_obj_t* icon;
+ lv_obj_t* condition;
+ lv_obj_t* temperature;
+ lv_obj_t* minTemperature;
+ lv_obj_t* maxTemperature;
+ lv_obj_t* forecast;
- std::unique_ptr<Screen> CreateScreenClouds();
+ lv_task_t* taskRefresh;
+ };
+ }
- std::unique_ptr<Screen> CreateScreenPrecipitation();
+ template <>
+ struct AppTraits<Apps::Weather> {
+ static constexpr Apps app = Apps::Weather;
+ static constexpr const char* icon = Screens::Symbols::cloudSunRain;
- std::unique_ptr<Screen> CreateScreenHumidity();
+ static Screens::Screen* Create(AppControllers& controllers) {
+ return new Screens::Weather(controllers.settingsController, *controllers.weatherController);
};
- }
+ };
}
}
diff --git a/src/displayapp/screens/WeatherSymbols.cpp b/src/displayapp/screens/WeatherSymbols.cpp
new file mode 100644
index 00000000..de66312f
--- /dev/null
+++ b/src/displayapp/screens/WeatherSymbols.cpp
@@ -0,0 +1,61 @@
+#include "displayapp/screens/WeatherSymbols.h"
+
+const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon) {
+ switch (icon) {
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Sun:
+ return Symbols::sun;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun:
+ return Symbols::cloudSun;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds:
+ return Symbols::cloud;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds:
+ return Symbols::cloudMeatball;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm:
+ return Symbols::bolt;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Snow:
+ return Symbols::snowflake;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy:
+ return Symbols::cloudShowersHeavy;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain:
+ return Symbols::cloudSunRain;
+ break;
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Smog:
+ return Symbols::smog;
+ break;
+ default:
+ return Symbols::ban;
+ break;
+ }
+}
+
+const char* Pinetime::Applications::Screens::Symbols::GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon) {
+ switch (icon) {
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Sun:
+ return "Clear sky";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun:
+ return "Few clouds";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds:
+ return "Scattered clouds";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds:
+ return "Broken clouds";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy:
+ return "Shower rain";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain:
+ return "Rain";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm:
+ return "Thunderstorm";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Snow:
+ return "Snow";
+ case Pinetime::Controllers::SimpleWeatherService::Icons::Smog:
+ return "Mist";
+ default:
+ return "";
+ }
+}
diff --git a/src/displayapp/screens/WeatherSymbols.h b/src/displayapp/screens/WeatherSymbols.h
new file mode 100644
index 00000000..f3eeed55
--- /dev/null
+++ b/src/displayapp/screens/WeatherSymbols.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "components/ble/SimpleWeatherService.h"
+#include "displayapp/screens/Symbols.h"
+
+namespace Pinetime {
+ namespace Applications {
+ namespace Screens {
+ namespace Symbols {
+ const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
+ const char* GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
+ }
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp
index 05484888..c5c3071a 100644
--- a/src/displayapp/screens/settings/QuickSettings.cpp
+++ b/src/displayapp/screens/settings/QuickSettings.cpp
@@ -33,13 +33,14 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
Controllers::BrightnessController& brightness,
Controllers::MotorController& motorController,
Pinetime::Controllers::Settings& settingsController,
- const Controllers::Ble& bleController)
+ const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController)
: app {app},
dateTimeController {dateTimeController},
brightness {brightness},
motorController {motorController},
settingsController {settingsController},
- statusIcons(batteryController, bleController) {
+ statusIcons(batteryController, bleController, alarmController) {
statusIcons.Create();
diff --git a/src/displayapp/screens/settings/QuickSettings.h b/src/displayapp/screens/settings/QuickSettings.h
index 55da6176..87c126b7 100644
--- a/src/displayapp/screens/settings/QuickSettings.h
+++ b/src/displayapp/screens/settings/QuickSettings.h
@@ -23,7 +23,8 @@ namespace Pinetime {
Controllers::BrightnessController& brightness,
Controllers::MotorController& motorController,
Pinetime::Controllers::Settings& settingsController,
- const Controllers::Ble& bleController);
+ const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController);
~QuickSettings() override;
diff --git a/src/displayapp/screens/settings/SettingBluetooth.cpp b/src/displayapp/screens/settings/SettingBluetooth.cpp
index 82c3dee1..e4dc695c 100644
--- a/src/displayapp/screens/settings/SettingBluetooth.cpp
+++ b/src/displayapp/screens/settings/SettingBluetooth.cpp
@@ -36,17 +36,19 @@ namespace {
SettingBluetooth::SettingBluetooth(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: app {app},
+ settings {settingsController},
checkboxList(
0,
1,
"Bluetooth",
Symbols::bluetooth,
settingsController.GetBleRadioEnabled() ? 0 : 1,
- [&settings = settingsController](uint32_t index) {
+ [this](uint32_t index) {
const bool priorMode = settings.GetBleRadioEnabled();
const bool newMode = options[index].radioEnabled;
if (newMode != priorMode) {
settings.SetBleRadioEnabled(newMode);
+ this->app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle);
}
},
CreateOptionArray()) {
@@ -54,6 +56,4 @@ SettingBluetooth::SettingBluetooth(Pinetime::Applications::DisplayApp* app, Pine
SettingBluetooth::~SettingBluetooth() {
lv_obj_clean(lv_scr_act());
- // Pushing the message in the OnValueChanged function causes a freeze?
- app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle);
}
diff --git a/src/displayapp/screens/settings/SettingBluetooth.h b/src/displayapp/screens/settings/SettingBluetooth.h
index 1e3f9b81..0cf014f5 100644
--- a/src/displayapp/screens/settings/SettingBluetooth.h
+++ b/src/displayapp/screens/settings/SettingBluetooth.h
@@ -20,6 +20,7 @@ namespace Pinetime {
private:
DisplayApp* app;
+ Pinetime::Controllers::Settings& settings;
CheckboxList checkboxList;
};
}
diff --git a/src/displayapp/screens/settings/SettingDisplay.cpp b/src/displayapp/screens/settings/SettingDisplay.cpp
index a9476432..bbc188a9 100644
--- a/src/displayapp/screens/settings/SettingDisplay.cpp
+++ b/src/displayapp/screens/settings/SettingDisplay.cpp
@@ -9,16 +9,22 @@
using namespace Pinetime::Applications::Screens;
namespace {
- void event_handler(lv_obj_t* obj, lv_event_t event) {
+ void TimeoutEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<SettingDisplay*>(obj->user_data);
screen->UpdateSelected(obj, event);
}
+
+ void AlwaysOnEventHandler(lv_obj_t* obj, lv_event_t event) {
+ if (event == LV_EVENT_VALUE_CHANGED) {
+ auto* screen = static_cast<SettingDisplay*>(obj->user_data);
+ screen->ToggleAlwaysOn();
+ }
+ }
}
constexpr std::array<uint16_t, 6> SettingDisplay::options;
-SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
- : app {app}, settingsController {settingsController} {
+SettingDisplay::SettingDisplay(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} {
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
@@ -43,19 +49,26 @@ SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
- char buffer[12];
+ char buffer[4];
for (unsigned int i = 0; i < options.size(); i++) {
cbOption[i] = lv_checkbox_create(container1, nullptr);
- sprintf(buffer, "%2ds", options[i] / 1000);
+ snprintf(buffer, sizeof(buffer), "%2" PRIu16 "s", options[i] / 1000);
lv_checkbox_set_text(cbOption[i], buffer);
cbOption[i]->user_data = this;
- lv_obj_set_event_cb(cbOption[i], event_handler);
+ lv_obj_set_event_cb(cbOption[i], TimeoutEventHandler);
SetRadioButtonStyle(cbOption[i]);
if (settingsController.GetScreenTimeOut() == options[i]) {
lv_checkbox_set_checked(cbOption[i], true);
}
}
+
+ alwaysOnCheckbox = lv_checkbox_create(container1, nullptr);
+ lv_checkbox_set_text(alwaysOnCheckbox, "Always On");
+ lv_checkbox_set_checked(alwaysOnCheckbox, settingsController.GetAlwaysOnDisplaySetting());
+ lv_obj_add_state(alwaysOnCheckbox, LV_STATE_DEFAULT);
+ alwaysOnCheckbox->user_data = this;
+ lv_obj_set_event_cb(alwaysOnCheckbox, AlwaysOnEventHandler);
}
SettingDisplay::~SettingDisplay() {
@@ -63,13 +76,17 @@ SettingDisplay::~SettingDisplay() {
settingsController.SaveSettings();
}
+void SettingDisplay::ToggleAlwaysOn() {
+ settingsController.SetAlwaysOnDisplaySetting(!settingsController.GetAlwaysOnDisplaySetting());
+ lv_checkbox_set_checked(alwaysOnCheckbox, settingsController.GetAlwaysOnDisplaySetting());
+}
+
void SettingDisplay::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
for (unsigned int i = 0; i < options.size(); i++) {
if (object == cbOption[i]) {
lv_checkbox_set_checked(cbOption[i], true);
settingsController.SetScreenTimeOut(options[i]);
- app->PushMessage(Applications::Display::Messages::UpdateTimeOut);
} else {
lv_checkbox_set_checked(cbOption[i], false);
}
diff --git a/src/displayapp/screens/settings/SettingDisplay.h b/src/displayapp/screens/settings/SettingDisplay.h
index 64212c02..3bd10a62 100644
--- a/src/displayapp/screens/settings/SettingDisplay.h
+++ b/src/displayapp/screens/settings/SettingDisplay.h
@@ -14,17 +14,18 @@ namespace Pinetime {
class SettingDisplay : public Screen {
public:
- SettingDisplay(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
+ SettingDisplay(Pinetime::Controllers::Settings& settingsController);
~SettingDisplay() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event);
+ void ToggleAlwaysOn();
private:
- DisplayApp* app;
static constexpr std::array<uint16_t, 6> options = {5000, 7000, 10000, 15000, 20000, 30000};
Controllers::Settings& settingsController;
lv_obj_t* cbOption[options.size()];
+ lv_obj_t* alwaysOnCheckbox;
};
}
}
diff --git a/src/displayapp/screens/settings/SettingSetDateTime.cpp b/src/displayapp/screens/settings/SettingSetDateTime.cpp
index cf9b0638..8926ff31 100644
--- a/src/displayapp/screens/settings/SettingSetDateTime.cpp
+++ b/src/displayapp/screens/settings/SettingSetDateTime.cpp
@@ -15,8 +15,7 @@ bool SettingSetDateTime::OnTouchEvent(Pinetime::Applications::TouchEvents event)
SettingSetDateTime::SettingSetDateTime(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::DateTime& dateTimeController,
Pinetime::Controllers::Settings& settingsController)
- : app {app},
- dateTimeController {dateTimeController},
+ : dateTimeController {dateTimeController},
settingsController {settingsController},
screens {app,
0,
diff --git a/src/displayapp/screens/settings/SettingSetDateTime.h b/src/displayapp/screens/settings/SettingSetDateTime.h
index 051b1abe..dea283f8 100644
--- a/src/displayapp/screens/settings/SettingSetDateTime.h
+++ b/src/displayapp/screens/settings/SettingSetDateTime.h
@@ -20,7 +20,6 @@ namespace Pinetime {
void Quit();
private:
- DisplayApp* app;
Controllers::DateTime& dateTimeController;
Controllers::Settings& settingsController;
diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp
index 8df34c20..4649dc82 100644
--- a/src/displayapp/screens/settings/SettingWakeUp.cpp
+++ b/src/displayapp/screens/settings/SettingWakeUp.cpp
@@ -8,7 +8,7 @@
using namespace Pinetime::Applications::Screens;
-constexpr std::array<SettingWakeUp::Option, 4> SettingWakeUp::options;
+constexpr std::array<SettingWakeUp::Option, 5> SettingWakeUp::options;
namespace {
void event_handler(lv_obj_t* obj, lv_event_t event) {
@@ -27,9 +27,9 @@ SettingWakeUp::SettingWakeUp(Pinetime::Controllers::Settings& settingsController
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_pos(container1, 10, 35);
lv_obj_set_width(container1, LV_HOR_RES - 20);
- lv_obj_set_height(container1, LV_VER_RES - 50);
+ lv_obj_set_height(container1, LV_VER_RES - 20);
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h
index 28219ca1..61edabce 100644
--- a/src/displayapp/screens/settings/SettingWakeUp.h
+++ b/src/displayapp/screens/settings/SettingWakeUp.h
@@ -25,11 +25,12 @@ namespace Pinetime {
};
Controllers::Settings& settingsController;
- static constexpr std::array<Option, 4> options = {{
+ static constexpr std::array<Option, 5> options = {{
{Controllers::Settings::WakeUpMode::SingleTap, "Single Tap"},
{Controllers::Settings::WakeUpMode::DoubleTap, "Double Tap"},
{Controllers::Settings::WakeUpMode::RaiseWrist, "Raise Wrist"},
{Controllers::Settings::WakeUpMode::Shake, "Shake Wake"},
+ {Controllers::Settings::WakeUpMode::LowerWrist, "Lower Wrist"},
}};
lv_obj_t* cbOption[options.size()];
diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp
index 285efa72..0d5168d2 100644
--- a/src/displayapp/screens/settings/SettingWatchFace.cpp
+++ b/src/displayapp/screens/settings/SettingWatchFace.cpp
@@ -9,6 +9,37 @@ using namespace Pinetime::Applications::Screens;
constexpr const char* SettingWatchFace::title;
constexpr const char* SettingWatchFace::symbol;
+namespace {
+ uint32_t IndexOf(const std::array<Pinetime::Applications::Screens::SettingWatchFace::Item,
+ Pinetime::Applications::UserWatchFaceTypes::Count>& watchfaces,
+ Pinetime::Applications::WatchFace watchface) {
+ size_t index = 0;
+ auto found = std::find_if(watchfaces.begin(),
+ watchfaces.end(),
+ [&index, &watchface](const Pinetime::Applications::Screens::SettingWatchFace::Item& item) {
+ const bool result = item.watchface == watchface;
+ if (!result) {
+ index++;
+ }
+ return result;
+ });
+ if (found == watchfaces.end()) {
+ index = 0;
+ }
+
+ return index;
+ }
+
+ Pinetime::Applications::WatchFace IndexToWatchFace(const std::array<Pinetime::Applications::Screens::SettingWatchFace::Item,
+ Pinetime::Applications::UserWatchFaceTypes::Count>& watchfaces,
+ size_t index) {
+ if (index >= watchfaces.size()) {
+ return watchfaces[0].watchface;
+ }
+ return watchfaces[index].watchface;
+ }
+}
+
auto SettingWatchFace::CreateScreenList() const {
std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens;
for (size_t i = 0; i < screens.size(); i++) {
@@ -20,9 +51,10 @@ auto SettingWatchFace::CreateScreenList() const {
}
SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app,
+ std::array<Screens::SettingWatchFace::Item, UserWatchFaceTypes::Count>&& watchfaceItems,
Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::FS& filesystem)
- : app {app},
+ : watchfaceItems {std::move(watchfaceItems)},
settingsController {settingsController},
filesystem {filesystem},
screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} {
@@ -39,7 +71,12 @@ bool SettingWatchFace::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
std::unique_ptr<Screen> SettingWatchFace::CreateScreen(unsigned int screenNum) const {
std::array<Screens::CheckboxList::Item, settingsPerScreen> watchfacesOnThisScreen;
for (int i = 0; i < settingsPerScreen; i++) {
- watchfacesOnThisScreen[i] = watchfaces[screenNum * settingsPerScreen + i];
+ if (i + (screenNum * settingsPerScreen) >= watchfaceItems.size()) {
+ watchfacesOnThisScreen[i] = {"", false};
+ } else {
+ auto& item = watchfaceItems[i + (screenNum * settingsPerScreen)];
+ watchfacesOnThisScreen[i] = Screens::CheckboxList::Item {item.name, item.enabled};
+ }
}
return std::make_unique<Screens::CheckboxList>(
@@ -47,9 +84,9 @@ std::unique_ptr<Screen> SettingWatchFace::CreateScreen(unsigned int screenNum) c
nScreens,
title,
symbol,
- settingsController.GetClockFace(),
- [&settings = settingsController](uint32_t clockFace) {
- settings.SetClockFace(clockFace);
+ static_cast<uint32_t>(IndexOf(watchfaceItems, settingsController.GetWatchFace())),
+ [this, &settings = settingsController](uint32_t index) {
+ settings.SetWatchFace(IndexToWatchFace(watchfaceItems, index));
settings.SaveSettings();
},
watchfacesOnThisScreen);
diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h
index 45a50e3d..9edc1f7a 100644
--- a/src/displayapp/screens/settings/SettingWatchFace.h
+++ b/src/displayapp/screens/settings/SettingWatchFace.h
@@ -19,36 +19,34 @@ namespace Pinetime {
class SettingWatchFace : public Screen {
public:
- SettingWatchFace(DisplayApp* app, Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::FS& filesystem);
+ struct Item {
+ const char* name;
+ WatchFace watchface;
+ bool enabled;
+ };
+
+ SettingWatchFace(DisplayApp* app,
+ std::array<Item, UserWatchFaceTypes::Count>&& watchfaceItems,
+ Pinetime::Controllers::Settings& settingsController,
+ Pinetime::Controllers::FS& filesystem);
~SettingWatchFace() override;
bool OnTouchEvent(TouchEvents event) override;
private:
- DisplayApp* app;
auto CreateScreenList() const;
std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const;
+ static constexpr int settingsPerScreen = 4;
+ std::array<Item, UserWatchFaceTypes::Count> watchfaceItems;
+ static constexpr int nScreens = UserWatchFaceTypes::Count > 0 ? (UserWatchFaceTypes ::Count - 1) / settingsPerScreen + 1 : 1;
+
Controllers::Settings& settingsController;
Pinetime::Controllers::FS& filesystem;
static constexpr const char* title = "Watch face";
static constexpr const char* symbol = Symbols::home;
- static constexpr int settingsPerScreen = 4;
-
- // Increment this when more space is needed
- static constexpr int nScreens = 2;
-
- std::array<Screens::CheckboxList::Item, settingsPerScreen * nScreens> watchfaces {
- {{"Digital face", true},
- {"Analog face", true},
- {"PineTimeStyle", true},
- {"Terminal", true},
- {"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)},
- {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)},
- {"", false},
- {"", false}}};
ScreenList<nScreens> screens;
};
}
diff --git a/src/displayapp/screens/settings/SettingWeatherFormat.cpp b/src/displayapp/screens/settings/SettingWeatherFormat.cpp
new file mode 100644
index 00000000..22d281b2
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingWeatherFormat.cpp
@@ -0,0 +1,63 @@
+#include "displayapp/screens/settings/SettingWeatherFormat.h"
+
+#include <lvgl/lvgl.h>
+
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Styles.h"
+#include "displayapp/screens/Screen.h"
+#include "displayapp/screens/Symbols.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+ struct Option {
+ Pinetime::Controllers::Settings::WeatherFormat weatherFormat;
+ const char* name;
+ };
+
+ constexpr std::array<Option, 2> options = {{
+ {Pinetime::Controllers::Settings::WeatherFormat::Metric, "Metric"},
+ {Pinetime::Controllers::Settings::WeatherFormat::Imperial, "Imperial"},
+ }};
+
+ std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() {
+ std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray;
+ for (size_t i = 0; i < CheckboxList::MaxItems; i++) {
+ if (i >= options.size()) {
+ optionArray[i].name = "";
+ optionArray[i].enabled = false;
+ } else {
+ optionArray[i].name = options[i].name;
+ optionArray[i].enabled = true;
+ }
+ }
+ return optionArray;
+ }
+
+ uint32_t GetDefaultOption(Pinetime::Controllers::Settings::WeatherFormat currentOption) {
+ for (size_t i = 0; i < options.size(); i++) {
+ if (options[i].weatherFormat == currentOption) {
+ return i;
+ }
+ }
+ return 0;
+ }
+}
+
+SettingWeatherFormat::SettingWeatherFormat(Pinetime::Controllers::Settings& settingsController)
+ : checkboxList(
+ 0,
+ 1,
+ "Weather format",
+ Symbols::cloudSunRain,
+ GetDefaultOption(settingsController.GetWeatherFormat()),
+ [&settings = settingsController](uint32_t index) {
+ settings.SetWeatherFormat(options[index].weatherFormat);
+ settings.SaveSettings();
+ },
+ CreateOptionArray()) {
+}
+
+SettingWeatherFormat::~SettingWeatherFormat() {
+ lv_obj_clean(lv_scr_act());
+}
diff --git a/src/displayapp/screens/settings/SettingWeatherFormat.h b/src/displayapp/screens/settings/SettingWeatherFormat.h
new file mode 100644
index 00000000..a3d2bf4b
--- /dev/null
+++ b/src/displayapp/screens/settings/SettingWeatherFormat.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <lvgl/lvgl.h>
+
+#include "components/settings/Settings.h"
+#include "displayapp/screens/Screen.h"
+#include "displayapp/screens/CheckboxList.h"
+
+namespace Pinetime {
+
+ namespace Applications {
+ namespace Screens {
+
+ class SettingWeatherFormat : public Screen {
+ public:
+ explicit SettingWeatherFormat(Pinetime::Controllers::Settings& settingsController);
+ ~SettingWeatherFormat() override;
+
+ private:
+ CheckboxList checkboxList;
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/settings/Settings.cpp b/src/displayapp/screens/settings/Settings.cpp
index 065417fa..cb5ba413 100644
--- a/src/displayapp/screens/settings/Settings.cpp
+++ b/src/displayapp/screens/settings/Settings.cpp
@@ -1,7 +1,7 @@
#include "displayapp/screens/settings/Settings.h"
#include <lvgl/lvgl.h>
#include <functional>
-#include "displayapp/Apps.h"
+#include "displayapp/apps/Apps.h"
#include "displayapp/DisplayApp.h"
using namespace Pinetime::Applications::Screens;
diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h
index 3f809753..3722c2be 100644
--- a/src/displayapp/screens/settings/Settings.h
+++ b/src/displayapp/screens/settings/Settings.h
@@ -29,7 +29,7 @@ namespace Pinetime {
static constexpr int entriesPerScreen = 4;
// Increment this when more space is needed
- static constexpr int nScreens = 3;
+ static constexpr int nScreens = 4;
static constexpr std::array<List::Applications, entriesPerScreen * nScreens> entries {{
{Symbols::sun, "Display", Apps::SettingDisplay},
@@ -38,13 +38,15 @@ namespace Pinetime {
{Symbols::home, "Watch face", Apps::SettingWatchFace},
{Symbols::shoe, "Steps", Apps::SettingSteps},
- {Symbols::clock, "Date&Time", Apps::SettingSetDateTime},
+ {Symbols::clock, "Date & Time", Apps::SettingSetDateTime},
+ {Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat},
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
- {Symbols::clock, "Chimes", Apps::SettingChimes},
+ {Symbols::clock, "Chimes", Apps::SettingChimes},
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
{Symbols::check, "Firmware", Apps::FirmwareValidation},
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
+
{Symbols::list, "About", Apps::SysInfo},
// {Symbols::none, "None", Apps::None},
diff --git a/src/displayapp/widgets/StatusIcons.cpp b/src/displayapp/widgets/StatusIcons.cpp
index 423b53d9..777731a5 100644
--- a/src/displayapp/widgets/StatusIcons.cpp
+++ b/src/displayapp/widgets/StatusIcons.cpp
@@ -1,10 +1,13 @@
#include "displayapp/widgets/StatusIcons.h"
#include "displayapp/screens/Symbols.h"
+#include "components/alarm/AlarmController.h"
using namespace Pinetime::Applications::Widgets;
-StatusIcons::StatusIcons(const Controllers::Battery& batteryController, const Controllers::Ble& bleController)
- : batteryIcon(true), batteryController {batteryController}, bleController {bleController} {
+StatusIcons::StatusIcons(const Controllers::Battery& batteryController,
+ const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController)
+ : batteryIcon(true), batteryController {batteryController}, bleController {bleController}, alarmController {alarmController} {
}
void StatusIcons::Create() {
@@ -20,6 +23,9 @@ void StatusIcons::Create() {
batteryPlug = lv_label_create(container, nullptr);
lv_label_set_text_static(batteryPlug, Screens::Symbols::plug);
+ alarmIcon = lv_label_create(container, nullptr);
+ lv_label_set_text_static(alarmIcon, Screens::Symbols::bell);
+
batteryIcon.Create(container);
lv_obj_align(container, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
@@ -37,6 +43,11 @@ void StatusIcons::Update() {
batteryIcon.SetBatteryPercentage(batteryPercent);
}
+ alarmEnabled = alarmController.IsEnabled();
+ if (alarmEnabled.IsUpdated()) {
+ lv_obj_set_hidden(alarmIcon, !alarmEnabled.Get());
+ }
+
bleState = bleController.IsConnected();
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
diff --git a/src/displayapp/widgets/StatusIcons.h b/src/displayapp/widgets/StatusIcons.h
index 27e8b86a..5524e996 100644
--- a/src/displayapp/widgets/StatusIcons.h
+++ b/src/displayapp/widgets/StatusIcons.h
@@ -5,14 +5,18 @@
#include "displayapp/screens/Screen.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
+#include "components/alarm/AlarmController.h"
#include "displayapp/screens/BatteryIcon.h"
+#include "utility/DirtyValue.h"
namespace Pinetime {
namespace Applications {
namespace Widgets {
class StatusIcons {
public:
- StatusIcons(const Controllers::Battery& batteryController, const Controllers::Ble& bleController);
+ StatusIcons(const Controllers::Battery& batteryController,
+ const Controllers::Ble& bleController,
+ const Controllers::AlarmController& alarmController);
void Align();
void Create();
@@ -26,13 +30,16 @@ namespace Pinetime {
Screens::BatteryIcon batteryIcon;
const Pinetime::Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
+ const Controllers::AlarmController& alarmController;
- Screens::DirtyValue<uint8_t> batteryPercentRemaining {};
- Screens::DirtyValue<bool> powerPresent {};
- Screens::DirtyValue<bool> bleState {};
- Screens::DirtyValue<bool> bleRadioEnabled {};
+ Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
+ Utility::DirtyValue<bool> powerPresent {};
+ Utility::DirtyValue<bool> bleState {};
+ Utility::DirtyValue<bool> bleRadioEnabled {};
+ Utility::DirtyValue<bool> alarmEnabled {};
lv_obj_t* bleIcon;
+ lv_obj_t* alarmIcon;
lv_obj_t* batteryPlug;
lv_obj_t* container;
};