From bda96dc595aecb56739cc02de7e7d2d825927b7f Mon Sep 17 00:00:00 2001 From: Avamander Date: Thu, 10 Jun 2021 00:44:49 +0300 Subject: Initial Weather service skeleton --- src/displayapp/screens/Weather.h | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/displayapp/screens/Weather.h (limited to 'src/displayapp/screens/Weather.h') diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h new file mode 100644 index 00000000..8b393ca1 --- /dev/null +++ b/src/displayapp/screens/Weather.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include "Screen.h" +#include "ScreenList.h" + +namespace Pinetime { + namespace Controllers { + class DateTime; + class Battery; + class BrightnessController; + class Ble; + } + + namespace Drivers { + class WatchdogView; + } + + namespace Applications { + class DisplayApp; + + namespace Screens { + class Weather : public Screen { + public: + explicit Weather(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Battery& batteryController, + Pinetime::Controllers::BrightnessController& brightnessController, + Pinetime::Controllers::Ble& bleController, + Pinetime::Drivers::WatchdogView& watchdog); + ~Weather() override; + bool Refresh() override; + bool OnButtonPushed() override; + bool OnTouchEvent(TouchEvents event) override; + + private: + bool running = true; + + Pinetime::Controllers::DateTime& dateTimeController; + Pinetime::Controllers::Battery& batteryController; + Pinetime::Controllers::BrightnessController& brightnessController; + Pinetime::Controllers::Ble& bleController; + Pinetime::Drivers::WatchdogView& watchdog; + + ScreenList<5> screens; + std::unique_ptr CreateScreen1(); + std::unique_ptr CreateScreen2(); + std::unique_ptr CreateScreen3(); + std::unique_ptr CreateScreen4(); + std::unique_ptr CreateScreen5(); + }; + } + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 19c9667a3d597167241ebcb4dfefb4e0cac068df Mon Sep 17 00:00:00 2001 From: Avamander Date: Fri, 25 Jun 2021 01:18:56 +0300 Subject: Started initial work on the UI --- src/components/ble/weather/WeatherService.cpp | 55 ++++++----- src/components/ble/weather/WeatherService.h | 34 +++---- src/displayapp/screens/Weather.cpp | 133 ++++---------------------- src/displayapp/screens/Weather.h | 35 +++---- 4 files changed, 80 insertions(+), 177 deletions(-) (limited to 'src/displayapp/screens/Weather.h') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index ae7370b5..7d20867d 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -20,8 +20,8 @@ #include "libs/QCBOR/inc/qcbor/qcbor.h" #include "systemtask/SystemTask.h" -int WeatherCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - return static_cast(arg)->OnCommand(conn_handle, attr_handle, ctxt); +int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + return static_cast(arg)->OnCommand(connHandle, attrHandle, ctxt); } namespace Pinetime { @@ -39,7 +39,7 @@ namespace Pinetime { ASSERT(res == 0); } - int WeatherService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { + int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) { // TODO: Detect control messages if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); @@ -167,9 +167,9 @@ namespace Pinetime { } } - getCurrentPressure(); - tidyTimeline(); - getTimelineLength(); + GetCurrentPressure(); + TidyTimeline(); + GetTimelineLength(); QCBORDecode_ExitMap(&decodeContext); auto uErr = QCBORDecode_Finish(&decodeContext); @@ -201,29 +201,36 @@ namespace Pinetime { return 0; } - WeatherData::Location WeatherService::getCurrentLocation() const { + WeatherData::Location WeatherService::GetCurrentLocation() const { return WeatherData::Location(); } - WeatherData::Clouds WeatherService::getCurrentClouds() const { + + WeatherData::Clouds WeatherService::GetCurrentClouds() const { return WeatherData::Clouds(); } - WeatherData::Obscuration WeatherService::getCurrentObscuration() const { + + WeatherData::Obscuration WeatherService::GetCurrentObscuration() const { return WeatherData::Obscuration(); } - WeatherData::Precipitation WeatherService::getCurrentPrecipitation() const { + + WeatherData::Precipitation WeatherService::GetCurrentPrecipitation() const { return WeatherData::Precipitation(); } - WeatherData::Wind WeatherService::getCurrentWind() const { + + WeatherData::Wind WeatherService::GetCurrentWind() const { return WeatherData::Wind(); } - WeatherData::Temperature WeatherService::getCurrentTemperature() const { + + WeatherData::Temperature WeatherService::GetCurrentTemperature() const { return WeatherData::Temperature(); } - WeatherData::Humidity WeatherService::getCurrentHumidity() const { + + WeatherData::Humidity WeatherService::GetCurrentHumidity() const { return WeatherData::Humidity(); } - WeatherData::Pressure WeatherService::getCurrentPressure() const { - uint64_t currentTimestamp = getCurrentUNIXTimestamp(); + + WeatherData::Pressure WeatherService::GetCurrentPressure() const { + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : timeline) { if (header->eventType == WeatherData::eventtype::Pressure && header->timestamp + header->expires <= currentTimestamp) { return WeatherData::Pressure(); @@ -232,15 +239,15 @@ namespace Pinetime { return WeatherData::Pressure(); } - WeatherData::AirQuality WeatherService::getCurrentQuality() const { + WeatherData::AirQuality WeatherService::GetCurrentQuality() const { return WeatherData::AirQuality(); } - size_t WeatherService::getTimelineLength() const { + size_t WeatherService::GetTimelineLength() const { return timeline.size(); } - bool WeatherService::addEventToTimeline(std::unique_ptr event) { + bool WeatherService::AddEventToTimeline(std::unique_ptr event) { if (timeline.size() == timeline.max_size()) { return false; } @@ -249,8 +256,8 @@ namespace Pinetime { return true; } - bool WeatherService::hasTimelineEventOfType(const WeatherData::eventtype type) const { - uint64_t currentTimestamp = getCurrentUNIXTimestamp(); + bool WeatherService::HasTimelineEventOfType(const WeatherData::eventtype type) const { + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : timeline) { if (header->eventType == type && header->timestamp + header->expires <= currentTimestamp) { // TODO: Check if its currently valid @@ -260,7 +267,7 @@ namespace Pinetime { return false; } - void WeatherService::tidyTimeline() { + void WeatherService::TidyTimeline() { uint64_t timeCurrent = 0; timeline.erase(std::remove_if(std::begin(timeline), std::end(timeline), @@ -269,15 +276,15 @@ namespace Pinetime { }), std::end(timeline)); - std::sort(std::begin(timeline), std::end(timeline), compareTimelineEvents); + std::sort(std::begin(timeline), std::end(timeline), CompareTimelineEvents); } - bool WeatherService::compareTimelineEvents(const std::unique_ptr& first, + bool WeatherService::CompareTimelineEvents(const std::unique_ptr& first, const std::unique_ptr& second) { return first->timestamp > second->timestamp; } - uint64_t WeatherService::getCurrentUNIXTimestamp() const { + uint64_t WeatherService::GetCurrentUnixTimestamp() const { return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); } } diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 53dbebfb..786d4715 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -32,7 +32,7 @@ #include "WeatherData.h" #include -int WeatherCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg); +int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg); namespace Pinetime { namespace System { @@ -46,20 +46,20 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt); /* * Helper functions for quick access to currently valid data */ - WeatherData::Location getCurrentLocation() const; - WeatherData::Clouds getCurrentClouds() const; - WeatherData::Obscuration getCurrentObscuration() const; - WeatherData::Precipitation getCurrentPrecipitation() const; - WeatherData::Wind getCurrentWind() const; - WeatherData::Temperature getCurrentTemperature() const; - WeatherData::Humidity getCurrentHumidity() const; - WeatherData::Pressure getCurrentPressure() const; - WeatherData::AirQuality getCurrentQuality() const; + WeatherData::Location GetCurrentLocation() const; + WeatherData::Clouds GetCurrentClouds() const; + WeatherData::Obscuration GetCurrentObscuration() const; + WeatherData::Precipitation GetCurrentPrecipitation() const; + WeatherData::Wind GetCurrentWind() const; + WeatherData::Temperature GetCurrentTemperature() const; + WeatherData::Humidity GetCurrentHumidity() const; + WeatherData::Pressure GetCurrentPressure() const; + WeatherData::AirQuality GetCurrentQuality() const; /* * Management functions @@ -68,16 +68,16 @@ namespace Pinetime { * Adds an event to the timeline * @return */ - bool addEventToTimeline(std::unique_ptr event); + bool AddEventToTimeline(std::unique_ptr event); /** * Gets the current timeline length */ - size_t getTimelineLength() const; + size_t GetTimelineLength() const; /** * Checks if an event of a certain type exists in the timeline * @return */ - bool hasTimelineEventOfType(WeatherData::eventtype type) const; + bool HasTimelineEventOfType(const WeatherData::eventtype type) const; private: // 00030000-78fc-48fe-8e23-433b3a1942d0 @@ -125,18 +125,18 @@ namespace Pinetime { * Cleans up the timeline of expired events * @return result code */ - void tidyTimeline(); + void TidyTimeline(); /** * Compares two timeline events */ - static bool compareTimelineEvents(const std::unique_ptr& first, + static bool CompareTimelineEvents(const std::unique_ptr& first, const std::unique_ptr& second); /** * Returns current UNIX timestamp */ - uint64_t getCurrentUNIXTimestamp() const; + uint64_t GetCurrentUnixTimestamp() const; }; } } \ No newline at end of file diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 0ba53bea..a1278649 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -1,5 +1,6 @@ #include "Weather.h" #include +#include #include "../DisplayApp.h" #include "Label.h" #include "Version.h" @@ -12,22 +13,14 @@ using namespace Pinetime::Applications::Screens; -Weather::Weather(Pinetime::Applications::DisplayApp* app, - Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Battery& batteryController, - Pinetime::Controllers::BrightnessController& brightnessController, - Pinetime::Controllers::Ble& bleController, - Pinetime::Drivers::WatchdogView& watchdog) +Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::WeatherService& weather) : Screen(app), dateTimeController {dateTimeController}, - batteryController {batteryController}, - brightnessController {brightnessController}, - bleController {bleController}, - watchdog {watchdog}, + weatherService(weather), screens {app, 0, {[this]() -> std::unique_ptr { - return CreateScreen1(); + return CreateScreenTemperature(); }, [this]() -> std::unique_ptr { return CreateScreen2(); @@ -64,101 +57,30 @@ bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } -std::unique_ptr Weather::CreateScreen1() { +std::unique_ptr Weather::CreateScreenTemperature() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); + Controllers::WeatherData::Temperature current = weatherService.GetCurrentTemperature(); lv_label_set_text_fmt(label, - "#FFFF00 InfiniTime#\n\n" - "#444444 Version# %ld.%ld.%ld\n\n" - "#444444 Build date#\n" - "%s\n" - "%s\n", - Version::Major(), - Version::Minor(), - Version::Patch(), - __DATE__, - __TIME__); + "#FFFF00 Temperature#\n\n" + "#444444 %hd%%#°C \n\n" + "#444444 %hd#\n" + "%llu\n" + "%lu\n", + current.temperature, + 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(new Screens::Label(0, 5, app, label)); } std::unique_ptr Weather::CreateScreen2() { - auto batteryPercent = static_cast(batteryController.PercentRemaining()); - float batteryVoltage = batteryController.Voltage(); - - auto resetReason = [this]() { - switch (watchdog.ResetReason()) { - case Drivers::Watchdog::ResetReasons::Watchdog: - return "wtdg"; - case Drivers::Watchdog::ResetReasons::HardReset: - return "hardr"; - case Drivers::Watchdog::ResetReasons::NFC: - return "nfc"; - case Drivers::Watchdog::ResetReasons::SoftReset: - return "softr"; - case Drivers::Watchdog::ResetReasons::CpuLockup: - return "cpulock"; - case Drivers::Watchdog::ResetReasons::SystemOff: - return "off"; - case Drivers::Watchdog::ResetReasons::LpComp: - return "lpcomp"; - case Drivers::Watchdog::ResetReasons::DebugInterface: - return "dbg"; - case Drivers::Watchdog::ResetReasons::ResetPin: - return "rst"; - default: - return "?"; - } - }(); - // uptime - static constexpr uint32_t secondsInADay = 60 * 60 * 24; - static constexpr uint32_t secondsInAnHour = 60 * 60; - static constexpr uint32_t secondsInAMinute = 60; - uint32_t uptimeSeconds = dateTimeController.Uptime().count(); - uint32_t uptimeDays = (uptimeSeconds / secondsInADay); - uptimeSeconds = uptimeSeconds % secondsInADay; - uint32_t uptimeHours = uptimeSeconds / secondsInAnHour; - uptimeSeconds = uptimeSeconds % secondsInAnHour; - uint32_t uptimeMinutes = uptimeSeconds / secondsInAMinute; - uptimeSeconds = uptimeSeconds % secondsInAMinute; - // TODO handle more than 100 days of uptime - - if (batteryPercent == -1) - batteryPercent = 0; - - // hack to not use the flot functions from printf - uint8_t batteryVoltageBytes[2]; - batteryVoltageBytes[1] = static_cast(batteryVoltage); // truncate whole numbers - batteryVoltageBytes[0] = - static_cast((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over - // - lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - lv_label_set_text_fmt(label, - "#444444 Date# %02d/%02d/%04d\n" - "#444444 Time# %02d:%02d:%02d\n" - "#444444 Uptime#\n %02lud %02lu:%02lu:%02lu\n" - "#444444 Battery# %d%%/%1i.%02iv\n" - "#444444 Backlight# %s\n" - "#444444 Last reset# %s\n", - dateTimeController.Day(), - static_cast(dateTimeController.Month()), - dateTimeController.Year(), - dateTimeController.Hours(), - dateTimeController.Minutes(), - dateTimeController.Seconds(), - uptimeDays, - uptimeHours, - uptimeMinutes, - uptimeSeconds, - batteryPercent, - batteryVoltageBytes[1], - batteryVoltageBytes[0], - brightnessController.ToString(), - resetReason); + lv_label_set_text_fmt(label, "#444444 Date# %02d\n", dateTimeController.Day()); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); return std::unique_ptr(new Screens::Label(1, 4, app, label)); } @@ -169,28 +91,11 @@ std::unique_ptr Weather::CreateScreen3() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - auto& bleAddr = bleController.Address(); lv_label_set_text_fmt(label, - "#444444 BLE MAC#\n" - " %02x:%02x:%02x:%02x:%02x:%02x" - "\n" - "#444444 Memory#\n" - " #444444 used# %d (%d%%)\n" " #444444 frag# %d%%\n" - " #444444 free# %d" - "\n" - "#444444 Steps# %li", - bleAddr[5], - bleAddr[4], - bleAddr[3], - bleAddr[2], - bleAddr[1], - bleAddr[0], - (int) mon.total_size - mon.free_size, + " #444444 free# %d", mon.used_pct, - mon.frag_pct, - (int) mon.free_biggest_size, - 0); + mon.frag_pct); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); return std::unique_ptr(new Screens::Label(2, 5, app, label)); } @@ -201,7 +106,7 @@ bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) { std::unique_ptr Weather::CreateScreen4() { TaskStatus_t tasksStatus[7]; - lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL); + lv_obj_t* infoTask = lv_table_create(lv_scr_act(), nullptr); lv_table_set_col_cnt(infoTask, 3); lv_table_set_row_cnt(infoTask, 8); lv_obj_set_pos(infoTask, 10, 10); diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h index 8b393ca1..469bf592 100644 --- a/src/displayapp/screens/Weather.h +++ b/src/displayapp/screens/Weather.h @@ -1,52 +1,43 @@ #pragma once #include +#include #include "Screen.h" #include "ScreenList.h" namespace Pinetime { - namespace Controllers { - class DateTime; - class Battery; - class BrightnessController; - class Ble; - } - - namespace Drivers { - class WatchdogView; - } - namespace Applications { class DisplayApp; namespace Screens { class Weather : public Screen { public: - explicit Weather(DisplayApp* app, - Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Battery& batteryController, - Pinetime::Controllers::BrightnessController& brightnessController, - Pinetime::Controllers::Ble& bleController, - Pinetime::Drivers::WatchdogView& watchdog); + explicit Weather(DisplayApp* app, Pinetime::Controllers::WeatherService& weather); + ~Weather() override; + bool Refresh() override; + bool OnButtonPushed() override; + bool OnTouchEvent(TouchEvents event) override; private: bool running = true; Pinetime::Controllers::DateTime& dateTimeController; - Pinetime::Controllers::Battery& batteryController; - Pinetime::Controllers::BrightnessController& brightnessController; - Pinetime::Controllers::Ble& bleController; - Pinetime::Drivers::WatchdogView& watchdog; + Controllers::WeatherService& weatherService; ScreenList<5> screens; - std::unique_ptr CreateScreen1(); + + std::unique_ptr CreateScreenTemperature(); + std::unique_ptr CreateScreen2(); + std::unique_ptr CreateScreen3(); + std::unique_ptr CreateScreen4(); + std::unique_ptr CreateScreen5(); }; } -- cgit v1.2.3-70-g09d2 From ffb17357e74fd80a0381361a5cbc6bc481d28000 Mon Sep 17 00:00:00 2001 From: Avamander Date: Sun, 28 Nov 2021 15:33:06 +0200 Subject: Fixed a few compilation errors, fixed UUID. --- src/components/ble/weather/WeatherData.h | 4 ++-- src/components/ble/weather/WeatherService.cpp | 2 +- src/components/ble/weather/WeatherService.h | 2 +- src/displayapp/screens/Weather.cpp | 27 +++++++++++++++++++-------- src/displayapp/screens/Weather.h | 4 ++-- 5 files changed, 25 insertions(+), 14 deletions(-) (limited to 'src/displayapp/screens/Weather.h') diff --git a/src/components/ble/weather/WeatherData.h b/src/components/ble/weather/WeatherData.h index 9b424004..19b9709d 100644 --- a/src/components/ble/weather/WeatherData.h +++ b/src/components/ble/weather/WeatherData.h @@ -250,7 +250,7 @@ namespace Pinetime { class Location : public TimelineHeader { public: /** Location name */ - std::unique_ptr location; + std::string location; /** Altitude relative to sea level in meters */ int16_t altitude; /** Latitude, EPSG:3857 (Google Maps, Openstreetmaps datum) */ @@ -311,7 +311,7 @@ namespace Pinetime { * For chemical compounds use the molecular formula e.g. "NO2", "CO2", "O3" * For pollen use the genus, e.g. "Betula" for birch or "Alternaria" for that mold's spores */ - std::unique_ptr polluter; + std::string polluter; /** * Amount of the pollution in SI units, * otherwise it's going to be difficult to create UI, alerts diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 22c80837..bbaa21f0 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -87,7 +87,7 @@ namespace Pinetime { if (UsefulBuf_IsNULLOrEmptyC(String) != 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - airquality->polluter = std::make_unique(static_cast(String.ptr), String.len); + airquality->polluter = std::string(static_cast(String.ptr), String.len); int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); if (tmpAmount < 0) { diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 5504ea49..7bf60ee1 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -88,7 +88,7 @@ namespace Pinetime { // 0003yyxx-78fc-48fe-8e23-433b3a1942d0 static constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) { return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128}, - .value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x03, 0x00}}; + .value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, y, x, 0x03, 0x00}}; } ble_uuid128_t weatherUuid {BaseUuid()}; diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index ea96c9f2..025a3bd8 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -1,14 +1,26 @@ +/* Copyright (C) 2021 Avamander + + 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 . +*/ #include "Weather.h" #include #include -#include "../DisplayApp.h" #include "Label.h" -#include "Version.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" -#include "components/brightness/BrightnessController.h" -#include "components/datetime/DateTimeController.h" -#include "drivers/Watchdog.h" #include "components/ble/weather/WeatherData.h" using namespace Pinetime::Applications::Screens; @@ -41,11 +53,10 @@ Weather::~Weather() { lv_obj_clean(lv_scr_act()); } -bool Weather::Refresh() { +void Weather::Refresh() { if (running) { - screens.Refresh(); + // screens.Refresh(); } - return running; } bool Weather::OnButtonPushed() { diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h index 469bf592..99cf15ba 100644 --- a/src/displayapp/screens/Weather.h +++ b/src/displayapp/screens/Weather.h @@ -16,7 +16,7 @@ namespace Pinetime { ~Weather() override; - bool Refresh() override; + void Refresh() override; bool OnButtonPushed() override; @@ -42,4 +42,4 @@ namespace Pinetime { }; } } -} \ No newline at end of file +} -- cgit v1.2.3-70-g09d2 From c870f8ed302823e12018aa196d87937c92966d06 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 00:45:28 +0200 Subject: Bunch of bugs fixed, improved error handling, debug UI addition --- src/components/ble/weather/WeatherService.cpp | 127 ++++++++++++----------- src/components/ble/weather/WeatherService.h | 31 ++++-- src/displayapp/Apps.h | 1 + src/displayapp/screens/Weather.cpp | 144 ++++++++++++++++---------- src/displayapp/screens/Weather.h | 8 +- 5 files changed, 182 insertions(+), 129 deletions(-) (limited to 'src/displayapp/screens/Weather.h') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 42302610..4ec57d00 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -28,6 +28,7 @@ namespace Pinetime { namespace Controllers { WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController) : system(system), dateTimeController(dateTimeController) { + nullHeader = &nullTimelineheader; } void WeatherService::Init() { @@ -42,7 +43,7 @@ namespace Pinetime { int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) { // TODO: Detect control messages if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); + const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); if (packetLen <= 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } @@ -56,30 +57,28 @@ namespace Pinetime { // Always encodes to the smallest number of bytes based on the value int64_t tmpTimestamp = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); - if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS) { + uint8_t err = QCBORDecode_GetError(&decodeContext); + if (err != QCBOR_SUCCESS) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } int64_t tmpExpires = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); if (tmpExpires < 0 || tmpExpires > 4294967295) { - // TODO: Return better error? return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } int64_t tmpEventType = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", &tmpEventType); if (tmpEventType < 0 || tmpEventType > static_cast(WeatherData::eventtype::Length)) { - // TODO: Return better error? return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } switch (static_cast(tmpEventType)) { - // TODO: Populate case WeatherData::eventtype::AirQuality: { std::unique_ptr airquality = std::make_unique(); airquality->timestamp = tmpTimestamp; airquality->eventType = static_cast(tmpEventType); airquality->expires = tmpExpires; - UsefulBufC String; + UsefulBufC String; // TODO: Everything ok with lifecycle here? QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &String); if (UsefulBuf_IsNULLOrEmptyC(String) != 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; @@ -172,10 +171,9 @@ namespace Pinetime { } } - GetCurrentPressure(); - TidyTimeline(); - GetTimelineLength(); QCBORDecode_ExitMap(&decodeContext); + GetTimelineLength(); + TidyTimeline(); if (QCBORDecode_Finish(&decodeContext) != QCBOR_SUCCESS) { return BLE_ATT_ERR_INSUFFICIENT_RES; @@ -205,94 +203,103 @@ namespace Pinetime { return 0; } - WeatherData::Clouds WeatherService::GetCurrentClouds() const { + std::unique_ptr& WeatherService::GetCurrentClouds() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Clouds && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Clouds && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Obscuration WeatherService::GetCurrentObscuration() const { + std::unique_ptr& WeatherService::GetCurrentObscuration() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Obscuration && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Obscuration && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Precipitation WeatherService::GetCurrentPrecipitation() const { + std::unique_ptr& WeatherService::GetCurrentPrecipitation() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Precipitation && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Precipitation && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Wind WeatherService::GetCurrentWind() const { + std::unique_ptr& WeatherService::GetCurrentWind() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Wind && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Wind && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Temperature WeatherService::GetCurrentTemperature() const { + std::unique_ptr& WeatherService::GetCurrentTemperature() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Humidity WeatherService::GetCurrentHumidity() const { + std::unique_ptr& WeatherService::GetCurrentHumidity() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Humidity && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Humidity && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Pressure WeatherService::GetCurrentPressure() const { + std::unique_ptr& WeatherService::GetCurrentPressure() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Pressure && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Pressure && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::Location WeatherService::GetCurrentLocation() const { + std::unique_ptr& WeatherService::GetCurrentLocation() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::Location && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::Location && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } - WeatherData::AirQuality WeatherService::GetCurrentQuality() const { + std::unique_ptr& WeatherService::GetCurrentQuality() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - for (auto&& header : timeline) { - if (header->eventType == WeatherData::eventtype::AirQuality && header->timestamp + header->expires <= currentTimestamp) { - return reinterpret_cast(header); + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp)) { + return reinterpret_cast&>(header); } } - return {}; + + return reinterpret_cast&>(this->nullHeader); } size_t WeatherService::GetTimelineLength() const { @@ -311,8 +318,7 @@ namespace Pinetime { bool WeatherService::HasTimelineEventOfType(const WeatherData::eventtype type) const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : timeline) { - if (header->eventType == type && header->timestamp + header->expires <= currentTimestamp) { - // TODO: Check if its currently valid + if (header->eventType == type && isEventStillValid(header, currentTimestamp)) { return true; } } @@ -320,11 +326,11 @@ namespace Pinetime { } void WeatherService::TidyTimeline() { - uint64_t timeCurrent = 0; + uint64_t timeCurrent = GetCurrentUnixTimestamp(); timeline.erase(std::remove_if(std::begin(timeline), std::end(timeline), [&](std::unique_ptr const& header) { - return header->timestamp + header->expires > timeCurrent; + return isEventStillValid(header, timeCurrent); }), std::end(timeline)); @@ -336,6 +342,11 @@ namespace Pinetime { return first->timestamp > second->timestamp; } + bool WeatherService::isEventStillValid(const std::unique_ptr& header, const uint64_t currentTimestamp) { + // Not getting timestamp in isEventStillValid for more speed + return header->timestamp + header->expires <= currentTimestamp; + } + uint64_t WeatherService::GetCurrentUnixTimestamp() const { return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); } diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 43b2ee28..7accc49e 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -51,15 +51,15 @@ namespace Pinetime { /* * Helper functions for quick access to currently valid data */ - WeatherData::Location GetCurrentLocation() const; - WeatherData::Clouds GetCurrentClouds() const; - WeatherData::Obscuration GetCurrentObscuration() const; - WeatherData::Precipitation GetCurrentPrecipitation() const; - WeatherData::Wind GetCurrentWind() const; - WeatherData::Temperature GetCurrentTemperature() const; - WeatherData::Humidity GetCurrentHumidity() const; - WeatherData::Pressure GetCurrentPressure() const; - WeatherData::AirQuality GetCurrentQuality() const; + std::unique_ptr& GetCurrentLocation(); + std::unique_ptr& GetCurrentClouds(); + std::unique_ptr& GetCurrentObscuration(); + std::unique_ptr& GetCurrentPrecipitation(); + std::unique_ptr& GetCurrentWind(); + std::unique_ptr& GetCurrentTemperature(); + std::unique_ptr& GetCurrentHumidity(); + std::unique_ptr& GetCurrentPressure(); + std::unique_ptr& GetCurrentQuality(); /* * Management functions @@ -123,7 +123,6 @@ namespace Pinetime { /** * Cleans up the timeline of expired events - * @return result code */ void TidyTimeline(); @@ -137,6 +136,18 @@ namespace Pinetime { * Returns current UNIX timestamp */ uint64_t GetCurrentUnixTimestamp() const; + + /** + * Checks if the event hasn't gone past and expired + * + * @param header timeline event to check + * @param currentTimestamp what's the time right now + * @return if the event is valid + */ + static bool isEventStillValid(const std::unique_ptr& uniquePtr, const uint64_t timestamp); + + std::unique_ptr nullTimelineheader = std::make_unique(); + std::unique_ptr* nullHeader; }; } } diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index d340efee..1cf7e2a8 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -25,6 +25,7 @@ namespace Pinetime { Metronome, Motion, Steps, + Weather, QuickSettings, Settings, SettingWatchFace, diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 025a3bd8..132bee71 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -35,16 +35,16 @@ Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers: return CreateScreenTemperature(); }, [this]() -> std::unique_ptr { - return CreateScreen2(); + return CreateScreenAir(); }, [this]() -> std::unique_ptr { - return CreateScreen3(); + return CreateScreenClouds(); }, [this]() -> std::unique_ptr { - return CreateScreen4(); + return CreateScreenPrecipitation(); }, [this]() -> std::unique_ptr { - return CreateScreen5(); + return CreateScreenHumidity(); }}, Screens::ScreenListModes::UpDown} { } @@ -71,78 +71,108 @@ bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) { std::unique_ptr Weather::CreateScreenTemperature() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - Controllers::WeatherData::Temperature current = weatherService.GetCurrentTemperature(); - lv_label_set_text_fmt(label, - "#FFFF00 Temperature#\n\n" - "#444444 %hd%%#°C \n\n" - "#444444 %hd#\n" - "%llu\n" - "%lu\n", - current.temperature, - current.dewPoint, - current.timestamp, - current.expires); + std::unique_ptr& current = weatherService.GetCurrentTemperature(); + if (current->timestamp == 0) { + // Do not use the data, it's invalid + } else { + lv_label_set_text_fmt(label, + "#FFFF00 Temperature#\n\n" + "#444444 %hd%%#°C \n\n" + "#444444 %hd#\n\n" + "%llu\n" + "%lu\n", + current->temperature, + 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(new Screens::Label(0, 5, app, label)); } -std::unique_ptr Weather::CreateScreen2() { - // uptime +std::unique_ptr Weather::CreateScreenAir() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - lv_label_set_text_fmt(label, "#444444 Date# %02d\n", dateTimeController.Day()); + std::unique_ptr& current = weatherService.GetCurrentQuality(); + if (current->timestamp == 0) { + // Do not use the data, it's invalid + } 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, + 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(new Screens::Label(1, 4, app, label)); + return std::unique_ptr(new Screens::Label(0, 5, app, label)); } -std::unique_ptr Weather::CreateScreen3() { - lv_mem_monitor_t mon; - lv_mem_monitor(&mon); - +std::unique_ptr Weather::CreateScreenClouds() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - lv_label_set_text_fmt(label, - " #444444 frag# %d%%\n" - " #444444 free# %d", - mon.used_pct, - mon.frag_pct); + std::unique_ptr& current = weatherService.GetCurrentClouds(); + if (current->timestamp == 0) { + // Do not use the data, it's invalid + } 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(new Screens::Label(2, 5, app, label)); -} - -bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) { - return lhs.xTaskNumber < rhs.xTaskNumber; + return std::unique_ptr(new Screens::Label(0, 5, app, label)); } -std::unique_ptr Weather::CreateScreen4() { - lv_obj_t* infoTask = lv_table_create(lv_scr_act(), nullptr); - lv_table_set_col_cnt(infoTask, 3); - lv_table_set_row_cnt(infoTask, 8); - lv_obj_set_pos(infoTask, 10, 10); - - lv_table_set_cell_value(infoTask, 0, 0, "#"); - lv_table_set_col_width(infoTask, 0, 50); - lv_table_set_cell_value(infoTask, 0, 1, "Task"); - lv_table_set_col_width(infoTask, 1, 80); - lv_table_set_cell_value(infoTask, 0, 2, "Free"); - lv_table_set_col_width(infoTask, 2, 90); - - return std::unique_ptr(new Screens::Label(3, 5, app, infoTask)); +std::unique_ptr Weather::CreateScreenPrecipitation() { + lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_recolor(label, true); + std::unique_ptr& current = weatherService.GetCurrentPrecipitation(); + if (current->timestamp == 0) { + // Do not use the data, it's invalid + } 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); + } + 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(new Screens::Label(0, 5, app, label)); } -std::unique_ptr Weather::CreateScreen5() { +std::unique_ptr Weather::CreateScreenHumidity() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - lv_label_set_text_static(label, - "Software Licensed\n" - "under the terms of\n" - "the GNU General\n" - "Public License v3\n" - "#444444 Source code#\n" - "#FFFF00 https://github.com/#\n" - "#FFFF00 JF002/InfiniTime#"); + std::unique_ptr& current = weatherService.GetCurrentHumidity(); + if (current->timestamp == 0) { + // Do not use the data, it's invalid + } 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); + } 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(new Screens::Label(4, 5, app, label)); + return std::unique_ptr(new Screens::Label(0, 5, app, label)); } diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h index 99cf15ba..34f95fce 100644 --- a/src/displayapp/screens/Weather.h +++ b/src/displayapp/screens/Weather.h @@ -32,13 +32,13 @@ namespace Pinetime { std::unique_ptr CreateScreenTemperature(); - std::unique_ptr CreateScreen2(); + std::unique_ptr CreateScreenAir(); - std::unique_ptr CreateScreen3(); + std::unique_ptr CreateScreenClouds(); - std::unique_ptr CreateScreen4(); + std::unique_ptr CreateScreenPrecipitation(); - std::unique_ptr CreateScreen5(); + std::unique_ptr CreateScreenHumidity(); }; } } -- cgit v1.2.3-70-g09d2