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/components/ble/weather/WeatherService.cpp | 208 ++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 src/components/ble/weather/WeatherService.cpp (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp new file mode 100644 index 00000000..006fc6c1 --- /dev/null +++ b/src/components/ble/weather/WeatherService.cpp @@ -0,0 +1,208 @@ +/* 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 +#include "WeatherService.h" +#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); +} + +namespace Pinetime { + namespace Controllers { + WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController) + : system(system), dateTimeController(dateTimeController) { + } + + void WeatherService::Init() { + uint8_t res = 0; + res = ble_gatts_count_cfg(serviceDefinition); + ASSERT(res == 0) + + res = ble_gatts_add_svcs(serviceDefinition); + ASSERT(res == 0); + } + + int WeatherService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + getCurrentPressure(); + tidyTimeline(); + getTimelineLength(); + const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); + if (packetLen <= 0) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + // Decode + QCBORDecodeContext decodeContext; + UsefulBufC EncodedCBOR; + // TODO: Check uninit fine + QCBORDecode_Init(&decodeContext, EncodedCBOR, QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterMap(&decodeContext, nullptr); + WeatherData::timelineheader timelineHeader {}; + // Always encodes to the smallest number of bytes based on the value + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", reinterpret_cast(&(timelineHeader.timestamp))); + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", reinterpret_cast(&(timelineHeader.expires))); + QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", reinterpret_cast(&(timelineHeader.eventType))); + switch (timelineHeader.eventType) { + // TODO: Populate + case WeatherData::eventtype::AirQuality: { + break; + } + case WeatherData::eventtype::Obscuration: { + break; + } + case WeatherData::eventtype::Precipitation: { + break; + } + case WeatherData::eventtype::Wind: { + break; + } + case WeatherData::eventtype::Temperature: { + break; + } + case WeatherData::eventtype::Special: { + break; + } + case WeatherData::eventtype::Pressure: { + break; + } + case WeatherData::eventtype::Location: { + break; + } + case WeatherData::eventtype::Clouds: { + break; + } + default: { + break; + } + } + QCBORDecode_ExitMap(&decodeContext); + + auto uErr = QCBORDecode_Finish(&decodeContext); + if (uErr != 0) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + // TODO: Detect control messages + + // Encode + uint8_t buffer[64]; + QCBOREncodeContext encodeContext; + QCBOREncode_Init(&encodeContext, UsefulBuf_FROM_BYTE_ARRAY(buffer)); + QCBOREncode_OpenMap(&encodeContext); + QCBOREncode_AddTextToMap(&encodeContext, "test", UsefulBuf_FROM_SZ_LITERAL("test")); + QCBOREncode_AddInt64ToMap(&encodeContext, "test", 1ul); + QCBOREncode_CloseMap(&encodeContext); + + UsefulBufC encodedEvent; + auto uErr = QCBOREncode_Finish(&encodeContext, &encodedEvent); + if (uErr != 0) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + auto res = os_mbuf_append(ctxt->om, &buffer, sizeof(buffer)); + if (res == 0) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + return 0; + } + return 0; + } + + WeatherData::location WeatherService::getCurrentLocation() const { + return WeatherData::location(); + } + WeatherData::clouds WeatherService::getCurrentClouds() const { + return WeatherData::clouds(); + } + WeatherData::obscuration WeatherService::getCurrentObscuration() const { + return WeatherData::obscuration(); + } + WeatherData::precipitation WeatherService::getCurrentPrecipitation() const { + return WeatherData::precipitation(); + } + WeatherData::wind WeatherService::getCurrentWind() const { + return WeatherData::wind(); + } + WeatherData::temperature WeatherService::getCurrentTemperature() const { + return WeatherData::temperature(); + } + WeatherData::humidity WeatherService::getCurrentHumidity() const { + return WeatherData::humidity(); + } + 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(); + } + } + return WeatherData::pressure(); + } + + WeatherData::airquality WeatherService::getCurrentQuality() const { + return WeatherData::airquality(); + } + + size_t WeatherService::getTimelineLength() const { + return timeline.size(); + } + + bool WeatherService::addEventToTimeline(std::unique_ptr event) { + if (timeline.size() == timeline.max_size()) { + return false; + } + + timeline.push_back(std::move(event)); + return true; + } + + 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 + return true; + } + } + return false; + } + + void WeatherService::tidyTimeline() { + uint64_t timeCurrent = 0; + timeline.erase(std::remove_if(std::begin(timeline), + std::end(timeline), + [&](std::unique_ptr const& header) { + return header->timestamp + header->expires > timeCurrent; + }), + std::end(timeline)); + + std::sort(std::begin(timeline), std::end(timeline), compareTimelineEvents); + } + + bool WeatherService::compareTimelineEvents(const std::unique_ptr& first, + const std::unique_ptr& second) { + return first->timestamp > second->timestamp; + } + + uint64_t WeatherService::getCurrentUNIXTimestamp() const { + return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); + } + } +} -- cgit v1.2.3-70-g09d2 From 6e165848161b72d1afa43af6807c654d3fc23d03 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 16 Jun 2021 23:31:17 +0300 Subject: Skeleton of the receiving logic --- src/components/ble/weather/WeatherData.h | 37 ++++--- src/components/ble/weather/WeatherService.cpp | 139 +++++++++++++++++++------- src/components/ble/weather/WeatherService.h | 45 ++++----- 3 files changed, 145 insertions(+), 76 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherData.h b/src/components/ble/weather/WeatherData.h index c1d53f4e..7cf68418 100644 --- a/src/components/ble/weather/WeatherData.h +++ b/src/components/ble/weather/WeatherData.h @@ -39,7 +39,7 @@ namespace Pinetime { None = 0, /** Water particles suspended in the air; low visibility; does not fall */ Fog = 1, - /** Extremely small, dry particles in the air; invisible to the eye; opalescent */ + /** Tiny, dry particles in the air; invisible to the eye; opalescent */ Haze = 2, /** Small fire-created particles suspended in the air */ Smoke = 3, @@ -51,6 +51,7 @@ namespace Pinetime { Sand = 6, /** Water particles suspended in the air; low-ish visibility; temperature is near dewpoint */ Mist = 7, + Length }; /** @@ -82,7 +83,8 @@ namespace Pinetime { /** Frozen drizzle; very small snow crystals */ SnowGrains = 8, /** Needles; columns or plates of ice. Sometimes described as "diamond dust". In very cold regions */ - IceCrystals = 9 + IceCrystals = 9, + Length }; /** @@ -99,6 +101,7 @@ namespace Pinetime { Fire = 3, /** Thunder and/or lightning */ Thunder = 4, + Length }; /** @@ -111,7 +114,8 @@ namespace Pinetime { /** This wipes the entire timeline */ DelTimeline = 1, /** There's a currently valid timeline event with the given type */ - HasValidEvent = 3 + HasValidEvent = 3, + Length }; /** @@ -137,19 +141,20 @@ namespace Pinetime { Location = 7, /** @see cloud */ Clouds = 8, + Length }; /** * Valid event query */ - class valideventquery { + class ValidEventQuery { public: static constexpr controlcodes code = controlcodes::HasValidEvent; eventtype eventType; }; /** The header used for further parsing */ - class timelineheader { + class TimelineHeader { public: /** UNIX timestamp */ uint64_t timestamp; @@ -168,23 +173,23 @@ namespace Pinetime { }; /** Specifies how cloudiness is stored */ - class clouds : public timelineheader { + class Clouds : public TimelineHeader { public: /** Cloud coverage in percentage, 0-100% */ uint8_t amount; }; /** Specifies how obscuration is stored */ - class obscuration : public timelineheader { + class Obscuration : public TimelineHeader { public: /** Type */ obscurationtype type; /** Visibility distance in meters */ - uint8_t amount; + uint16_t amount; }; /** Specifies how precipitation is stored */ - class precipitation : public timelineheader { + class Precipitation : public TimelineHeader { public: /** Type */ precipitationtype type; @@ -201,7 +206,7 @@ namespace Pinetime { * As direction can fluctuate wildly and some watchfaces might wish to display it nicely, * we're following the aerospace industry weather report option of specifying a range. */ - class wind : public timelineheader { + class Wind : public TimelineHeader { public: /** Meters per second */ uint8_t speedMin; @@ -221,7 +226,7 @@ namespace Pinetime { * * We don't do floats, microdegrees are not useful. Make sure to multiply. */ - class temperature : public timelineheader { + class Temperature : public TimelineHeader { public: /** Temperature °C but multiplied by 100 (e.g. -12.50°C becomes -1250) */ int16_t temperature; @@ -240,7 +245,7 @@ namespace Pinetime { * or daylight calculations, should those be required. * */ - class location : public timelineheader { + class Location : public TimelineHeader { public: /** Location name */ std::string location; @@ -255,7 +260,7 @@ namespace Pinetime { /** * How humidity is stored */ - class humidity : public timelineheader { + class Humidity : public TimelineHeader { public: /** Relative humidity, 0-100% */ uint8_t humidity; @@ -264,7 +269,7 @@ namespace Pinetime { /** * How air pressure is stored */ - class pressure : public timelineheader { + class Pressure : public TimelineHeader { public: /** Air pressure in hectopascals (hPa) */ int16_t pressure; @@ -273,7 +278,7 @@ namespace Pinetime { /** * How special events are stored */ - class special : public timelineheader { + class Special : public TimelineHeader { public: /** Special event's type */ specialtype type; @@ -288,7 +293,7 @@ namespace Pinetime { * * If this needs further enforced standardization, pull requests are welcome */ - class airquality : public timelineheader { + class AirQuality : public TimelineHeader { public: /** * The name of the pollution diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 006fc6c1..60e608e7 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -40,58 +40,125 @@ namespace Pinetime { } int WeatherService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { + // TODO: Detect control messages if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - getCurrentPressure(); - tidyTimeline(); - getTimelineLength(); const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); if (packetLen <= 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } // Decode QCBORDecodeContext decodeContext; - UsefulBufC EncodedCBOR; - // TODO: Check uninit fine - QCBORDecode_Init(&decodeContext, EncodedCBOR, QCBOR_DECODE_MODE_NORMAL); + UsefulBufC encodedCbor; + // TODO: Check, uninit fine? + + QCBORDecode_Init(&decodeContext, encodedCbor, QCBOR_DECODE_MODE_NORMAL); QCBORDecode_EnterMap(&decodeContext, nullptr); - WeatherData::timelineheader timelineHeader {}; // Always encodes to the smallest number of bytes based on the value - QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", reinterpret_cast(&(timelineHeader.timestamp))); - QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", reinterpret_cast(&(timelineHeader.expires))); - QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", reinterpret_cast(&(timelineHeader.eventType))); - switch (timelineHeader.eventType) { - // TODO: Populate + int64_t tmpVersion = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Version", &tmpVersion); + if (tmpVersion != 1) { + // TODO: Return better error? + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + int64_t tmpTimestamp = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); + int64_t tmpExpires = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); + if (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 > 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; + + timeline.push_back(std::move(airquality)); break; } case WeatherData::eventtype::Obscuration: { + std::unique_ptr obscuration = std::make_unique(); + obscuration->timestamp = tmpTimestamp; + obscuration->eventType = static_cast(tmpEventType); + obscuration->expires = tmpExpires; + + timeline.push_back(std::move(obscuration)); break; } case WeatherData::eventtype::Precipitation: { + std::unique_ptr precipitation = std::make_unique(); + precipitation->timestamp = tmpTimestamp; + precipitation->eventType = static_cast(tmpEventType); + precipitation->expires = tmpExpires; + timeline.push_back(std::move(precipitation)); break; } case WeatherData::eventtype::Wind: { + std::unique_ptr wind = std::make_unique(); + wind->timestamp = tmpTimestamp; + wind->eventType = static_cast(tmpEventType); + wind->expires = tmpExpires; + timeline.push_back(std::move(wind)); break; } case WeatherData::eventtype::Temperature: { + std::unique_ptr temperature = std::make_unique(); + temperature->timestamp = tmpTimestamp; + temperature->eventType = static_cast(tmpEventType); + temperature->expires = tmpExpires; + timeline.push_back(std::move(temperature)); break; } case WeatherData::eventtype::Special: { + std::unique_ptr special = std::make_unique(); + special->timestamp = tmpTimestamp; + special->eventType = static_cast(tmpEventType); + special->expires = tmpExpires; + timeline.push_back(std::move(special)); break; } case WeatherData::eventtype::Pressure: { + std::unique_ptr pressure = std::make_unique(); + pressure->timestamp = tmpTimestamp; + pressure->eventType = static_cast(tmpEventType); + pressure->expires = tmpExpires; + timeline.push_back(std::move(pressure)); break; } case WeatherData::eventtype::Location: { + std::unique_ptr location = std::make_unique(); + location->timestamp = tmpTimestamp; + location->eventType = static_cast(tmpEventType); + location->expires = tmpExpires; + timeline.push_back(std::move(location)); break; } case WeatherData::eventtype::Clouds: { + std::unique_ptr clouds = std::make_unique(); + clouds->timestamp = tmpTimestamp; + clouds->eventType = static_cast(tmpEventType); + clouds->expires = tmpExpires; + timeline.push_back(std::move(clouds)); break; } default: { break; } } + + getCurrentPressure(); + tidyTimeline(); + getTimelineLength(); QCBORDecode_ExitMap(&decodeContext); auto uErr = QCBORDecode_Finish(&decodeContext); @@ -99,8 +166,6 @@ namespace Pinetime { return BLE_ATT_ERR_INSUFFICIENT_RES; } } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - // TODO: Detect control messages - // Encode uint8_t buffer[64]; QCBOREncodeContext encodeContext; @@ -125,46 +190,46 @@ namespace Pinetime { return 0; } - WeatherData::location WeatherService::getCurrentLocation() const { - return WeatherData::location(); + WeatherData::Location WeatherService::getCurrentLocation() const { + return WeatherData::Location(); } - WeatherData::clouds WeatherService::getCurrentClouds() const { - return WeatherData::clouds(); + WeatherData::Clouds WeatherService::getCurrentClouds() const { + return WeatherData::Clouds(); } - WeatherData::obscuration WeatherService::getCurrentObscuration() const { - return WeatherData::obscuration(); + WeatherData::Obscuration WeatherService::getCurrentObscuration() const { + return WeatherData::Obscuration(); } - WeatherData::precipitation WeatherService::getCurrentPrecipitation() const { - return WeatherData::precipitation(); + WeatherData::Precipitation WeatherService::getCurrentPrecipitation() const { + return WeatherData::Precipitation(); } - WeatherData::wind WeatherService::getCurrentWind() const { - return WeatherData::wind(); + WeatherData::Wind WeatherService::getCurrentWind() const { + return WeatherData::Wind(); } - WeatherData::temperature WeatherService::getCurrentTemperature() const { - return WeatherData::temperature(); + WeatherData::Temperature WeatherService::getCurrentTemperature() const { + return WeatherData::Temperature(); } - WeatherData::humidity WeatherService::getCurrentHumidity() const { - return WeatherData::humidity(); + WeatherData::Humidity WeatherService::getCurrentHumidity() const { + return WeatherData::Humidity(); } - WeatherData::pressure WeatherService::getCurrentPressure() const { + 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(); + return WeatherData::Pressure(); } } - return WeatherData::pressure(); + return WeatherData::Pressure(); } - WeatherData::airquality WeatherService::getCurrentQuality() const { - return WeatherData::airquality(); + WeatherData::AirQuality WeatherService::getCurrentQuality() const { + return WeatherData::AirQuality(); } 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; } @@ -188,7 +253,7 @@ namespace Pinetime { uint64_t timeCurrent = 0; timeline.erase(std::remove_if(std::begin(timeline), std::end(timeline), - [&](std::unique_ptr const& header) { + [&](std::unique_ptr const& header) { return header->timestamp + header->expires > timeCurrent; }), std::end(timeline)); @@ -196,8 +261,8 @@ namespace Pinetime { std::sort(std::begin(timeline), std::end(timeline), compareTimelineEvents); } - bool WeatherService::compareTimelineEvents(const std::unique_ptr& first, - const std::unique_ptr& second) { + bool WeatherService::compareTimelineEvents(const std::unique_ptr& first, + const std::unique_ptr& second) { return first->timestamp > second->timestamp; } diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index ef99db86..64a8213a 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -57,15 +57,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; + 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 @@ -74,7 +74,7 @@ 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 */ @@ -86,37 +86,36 @@ namespace Pinetime { bool hasTimelineEventOfType(WeatherData::eventtype type) const; private: - ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_UUID_BASE}; + ble_uuid128_t weatherUUID {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_UUID_BASE}; /** * Just write timeline data here */ - ble_uuid128_t wDataCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x01)}; + ble_uuid128_t weatherDataCharUUID {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x01)}; /** - * This doesn't take timeline data - * but provides some control over it + * This doesn't take timeline data, + * provides some control over it */ - ble_uuid128_t wControlCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x02)}; + ble_uuid128_t weatherControlCharUUID {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x02)}; - const struct ble_gatt_chr_def characteristicDefinition[2] = {{.uuid = reinterpret_cast(&wDataCharUuid), + const struct ble_gatt_chr_def characteristicDefinition[2] = {{.uuid = &weatherDataCharUUID.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_NOTIFY, .val_handle = &eventHandle}, - {.uuid = reinterpret_cast(&wControlCharUuid), + {.uuid = &weatherControlCharUUID.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}}; const struct ble_gatt_svc_def serviceDefinition[2] = { - {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = reinterpret_cast(&msUuid), .characteristics = characteristicDefinition}, - {0}}; + {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &weatherUUID.u, .characteristics = characteristicDefinition}, {0}}; uint16_t eventHandle {}; Pinetime::System::SystemTask& system; Pinetime::Controllers::DateTime& dateTimeController; - std::vector> timeline; + std::vector> timeline; /** * Cleans up the timeline of expired events @@ -127,11 +126,11 @@ namespace Pinetime { /** * Compares two timeline events */ - static bool compareTimelineEvents(const std::unique_ptr& first, - const std::unique_ptr& second); + static bool compareTimelineEvents(const std::unique_ptr& first, + const std::unique_ptr& second); /** - * + * Returns current UNIX timestamp */ uint64_t getCurrentUNIXTimestamp() const; }; -- cgit v1.2.3-70-g09d2 From 4b2dcbb4f053a89faab50c03083c71fabf9f288a Mon Sep 17 00:00:00 2001 From: Avamander Date: Sun, 20 Jun 2021 21:37:53 +0300 Subject: Fixed a few bugs, enabled UsefulBuf library optimizations --- src/CMakeLists.txt | 1 + src/components/ble/NimbleController.h | 3 ++ src/components/ble/weather/WeatherData.h | 4 +-- src/components/ble/weather/WeatherService.cpp | 19 +++++++++--- src/components/ble/weather/WeatherService.h | 42 +++++++++++++++------------ 5 files changed, 44 insertions(+), 25 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb5e1d1e..4273becf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -860,6 +860,7 @@ target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_EXP_AND_MANTISSA) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_UNCOMMON_TAGS) +target_compile_definitions(QCBOR PUBLIC USEFULBUF_CONFIG_LITTLE_ENDIAN) set_target_properties(QCBOR PROPERTIES LINKER_LANGUAGE C) target_compile_options(QCBOR PRIVATE $<$,$>: ${COMMON_FLAGS} -O0 -g3> diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index a21cbe81..34f00e4e 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -71,6 +71,9 @@ namespace Pinetime { Pinetime::Controllers::AlertNotificationService& alertService() { return anService; }; + Pinetime::Controllers::WeatherService& weather() { + return weatherService; + }; uint16_t connHandle(); void NotifyBatteryLevel(uint8_t level); diff --git a/src/components/ble/weather/WeatherData.h b/src/components/ble/weather/WeatherData.h index 7cf68418..ee2a364d 100644 --- a/src/components/ble/weather/WeatherData.h +++ b/src/components/ble/weather/WeatherData.h @@ -248,7 +248,7 @@ namespace Pinetime { class Location : public TimelineHeader { public: /** Location name */ - std::string location; + std::unique_ptr location; /** Altitude relative to sea level in meters */ int16_t altitude; /** Latitude, EPSG:3857 (Google Maps, Openstreetmaps datum) */ @@ -309,7 +309,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::string polluter; + std::unique_ptr 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 60e608e7..30d274b2 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -33,7 +33,7 @@ namespace Pinetime { void WeatherService::Init() { uint8_t res = 0; res = ble_gatts_count_cfg(serviceDefinition); - ASSERT(res == 0) + ASSERT(res == 0); res = ble_gatts_add_svcs(serviceDefinition); ASSERT(res == 0); @@ -64,13 +64,13 @@ namespace Pinetime { QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); int64_t tmpExpires = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); - if (tmpExpires > 4294967295) { + 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 > static_cast(WeatherData::eventtype::Length)) { + if (tmpEventType < 0 || tmpEventType > static_cast(WeatherData::eventtype::Length)) { // TODO: Return better error? return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } @@ -82,7 +82,18 @@ namespace Pinetime { airquality->timestamp = tmpTimestamp; airquality->eventType = static_cast(tmpEventType); airquality->expires = tmpExpires; - + UsefulBufC String; + QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &String); + if (UsefulBuf_IsNULLOrEmptyC(String) != 0) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + airquality->polluter = std::make_unique(static_cast(String.ptr), String.len); + int64_t tmpAmount = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); + if (tmpAmount < 0 || tmpAmount > 4294967295) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + airquality->amount = tmpAmount; timeline.push_back(std::move(airquality)); break; } diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 64a8213a..43002dc1 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -32,12 +32,6 @@ #include "WeatherData.h" #include -// 00030000-78fc-48fe-8e23-433b3a1942d0 -#define WEATHER_SERVICE_UUID_BASE \ - { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x03, 0x00 } -#define WEATHER_SERVICE_CHAR_UUID(y, x) \ - { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, (x), (y), 0x03, 0x00 } - int WeatherCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg); namespace Pinetime { @@ -86,27 +80,37 @@ namespace Pinetime { bool hasTimelineEventOfType(WeatherData::eventtype type) const; private: - ble_uuid128_t weatherUUID {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_UUID_BASE}; + // 00030000-78fc-48fe-8e23-433b3a1942d0 + static constexpr ble_uuid128_t BaseUUID() { + return CharUUID(0x00, 0x00); + } + + // 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}}; + } + + ble_uuid128_t weatherUUID {BaseUUID()}; /** * Just write timeline data here */ - ble_uuid128_t weatherDataCharUUID {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x01)}; + ble_uuid128_t weatherDataCharUUID {CharUUID(0x00, 0x01)}; /** * This doesn't take timeline data, * provides some control over it */ - ble_uuid128_t weatherControlCharUUID {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x02)}; - - const struct ble_gatt_chr_def characteristicDefinition[2] = {{.uuid = &weatherDataCharUUID.u, - .access_cb = WeatherCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_NOTIFY, - .val_handle = &eventHandle}, - {.uuid = &weatherControlCharUUID.u, - .access_cb = WeatherCallback, - .arg = this, - .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}}; + ble_uuid128_t weatherControlCharUUID {CharUUID(0x00, 0x02)}; + + const struct ble_gatt_chr_def characteristicDefinition[3] = { + {.uuid = &weatherDataCharUUID.u, + .access_cb = WeatherCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = &eventHandle}, + {.uuid = &weatherControlCharUUID.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, + {nullptr}}; const struct ble_gatt_svc_def serviceDefinition[2] = { {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &weatherUUID.u, .characteristics = characteristicDefinition}, {0}}; -- cgit v1.2.3-70-g09d2 From 3a09b3614c19fda8f90af28b596a6359064ad0fb Mon Sep 17 00:00:00 2001 From: Avamander Date: Fri, 25 Jun 2021 00:43:30 +0300 Subject: Brace style and whitespace fixes --- src/CMakeLists.txt | 2 +- src/components/ble/weather/WeatherService.cpp | 2 +- src/components/ble/weather/WeatherService.h | 2 +- src/displayapp/screens/SystemInfo.cpp | 2 +- src/displayapp/screens/Weather.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4273becf..d83c467a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1153,4 +1153,4 @@ elseif (USE_OPENOCD) COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex" ) endif () -endif () +endif () \ No newline at end of file diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 30d274b2..ae7370b5 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -281,4 +281,4 @@ namespace Pinetime { return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); } } -} +} \ No newline at end of file diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 43002dc1..53dbebfb 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -139,4 +139,4 @@ namespace Pinetime { uint64_t getCurrentUNIXTimestamp() const; }; } -} +} \ No newline at end of file diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index c363e2dd..07626260 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -274,4 +274,4 @@ std::unique_ptr SystemInfo::CreateScreen5() { lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); return std::make_unique(4, 5, app, label); -} +} \ No newline at end of file diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 014761bf..0ba53bea 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -243,4 +243,4 @@ std::unique_ptr Weather::CreateScreen5() { 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)); -} +} \ 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/components/ble/weather/WeatherService.cpp') 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 0ed256ba15ceace2949f21ecbc1407b8553dd75d Mon Sep 17 00:00:00 2001 From: Avamander Date: Fri, 25 Jun 2021 02:52:59 +0300 Subject: Few formatting fixes --- src/CMakeLists.txt | 12 ++++++------ src/components/ble/weather/WeatherService.cpp | 2 +- src/components/ble/weather/WeatherService.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d83c467a..f1149ce5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -796,7 +796,7 @@ link_directories( ) -set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wno-unknown-pragmas -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type -fstack-usage -fno-exceptions -fno-non-call-exceptions) +set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -ftree-vrp -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type -fstack-usage -fno-exceptions -fno-non-call-exceptions) add_definitions(-DCONFIG_GPIO_AS_PINRESET) add_definitions(-DNIMBLE_CFG_CONTROLLER) add_definitions(-DOS_CPUTIME_FREQ) @@ -818,10 +818,10 @@ add_library(nrf-sdk STATIC ${SDK_SOURCE_FILES}) target_include_directories(nrf-sdk SYSTEM PUBLIC . ../) target_include_directories(nrf-sdk SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(nrf-sdk PRIVATE - $<$,$>: ${COMMON_FLAGS} -Og -g3> - $<$,$>: ${COMMON_FLAGS} -Os> - $<$,$>: ${COMMON_FLAGS} -Og -fno-rtti> - $<$,$>: ${COMMON_FLAGS} -Os -fno-rtti> + $<$,$>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -g3> + $<$,$>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3> + $<$,$>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -fno-rtti> + $<$,$>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3 -fno-rtti> $<$: -MP -MD -x assembler-with-cpp> ) @@ -1153,4 +1153,4 @@ elseif (USE_OPENOCD) COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex" ) endif () -endif () \ No newline at end of file +endif () diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 7d20867d..a9c9f114 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -288,4 +288,4 @@ namespace Pinetime { return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); } } -} \ No newline at end of file +} diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 786d4715..995f856e 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -139,4 +139,4 @@ namespace Pinetime { uint64_t GetCurrentUnixTimestamp() const; }; } -} \ No newline at end of file +} -- cgit v1.2.3-70-g09d2 From ed6f0aade4db811b5013441c57944baff4528938 Mon Sep 17 00:00:00 2001 From: Avamander Date: Sat, 21 Aug 2021 21:58:03 +0300 Subject: Implemented a few functions. --- src/components/ble/weather/WeatherData.h | 6 +- src/components/ble/weather/WeatherService.cpp | 84 ++++++++++++++++++++++----- src/components/ble/weather/WeatherService.h | 20 +++---- src/displayapp/screens/Weather.cpp | 16 +---- 4 files changed, 85 insertions(+), 41 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherData.h b/src/components/ble/weather/WeatherData.h index ee2a364d..9b424004 100644 --- a/src/components/ble/weather/WeatherData.h +++ b/src/components/ble/weather/WeatherData.h @@ -122,7 +122,7 @@ namespace Pinetime { * Events have types * then they're easier to parse after sending them over the air */ - enum class eventtype { + enum class eventtype : uint8_t { /** @see obscuration */ Obscuration = 0, /** @see precipitation */ @@ -141,6 +141,8 @@ namespace Pinetime { Location = 7, /** @see cloud */ Clouds = 8, + /** @see humidity */ + Humidity = 9, Length }; @@ -340,4 +342,4 @@ namespace Pinetime { }; }; } -} \ No newline at end of file +} diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index a9c9f114..22c80837 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -90,7 +90,7 @@ namespace Pinetime { airquality->polluter = std::make_unique(static_cast(String.ptr), String.len); int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); - if (tmpAmount < 0 || tmpAmount > 4294967295) { + if (tmpAmount < 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } airquality->amount = tmpAmount; @@ -162,6 +162,14 @@ namespace Pinetime { timeline.push_back(std::move(clouds)); break; } + case WeatherData::eventtype::Humidity: { + std::unique_ptr humidity = std::make_unique(); + humidity->timestamp = tmpTimestamp; + humidity->eventType = static_cast(tmpEventType); + humidity->expires = tmpExpires; + timeline.push_back(std::move(humidity)); + break; + } default: { break; } @@ -201,46 +209,94 @@ namespace Pinetime { return 0; } - WeatherData::Location WeatherService::GetCurrentLocation() const { - return WeatherData::Location(); - } - WeatherData::Clouds WeatherService::GetCurrentClouds() const { - return WeatherData::Clouds(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Clouds && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } WeatherData::Obscuration WeatherService::GetCurrentObscuration() const { - return WeatherData::Obscuration(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Obscuration && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } WeatherData::Precipitation WeatherService::GetCurrentPrecipitation() const { - return WeatherData::Precipitation(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Precipitation && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } WeatherData::Wind WeatherService::GetCurrentWind() const { - return WeatherData::Wind(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Wind && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } WeatherData::Temperature WeatherService::GetCurrentTemperature() const { - return WeatherData::Temperature(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } WeatherData::Humidity WeatherService::GetCurrentHumidity() const { - return WeatherData::Humidity(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Humidity && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } 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(); + return reinterpret_cast(header); + } + } + return {}; + } + + WeatherData::Location WeatherService::GetCurrentLocation() const { + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::Location && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); } } - return WeatherData::Pressure(); + return {}; } WeatherData::AirQuality WeatherService::GetCurrentQuality() const { - return WeatherData::AirQuality(); + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + for (auto&& header : timeline) { + if (header->eventType == WeatherData::eventtype::AirQuality && header->timestamp + header->expires <= currentTimestamp) { + return reinterpret_cast(header); + } + } + return {}; } size_t WeatherService::GetTimelineLength() const { diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 995f856e..5504ea49 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -77,42 +77,42 @@ namespace Pinetime { * Checks if an event of a certain type exists in the timeline * @return */ - bool HasTimelineEventOfType(const WeatherData::eventtype type) const; + bool HasTimelineEventOfType(WeatherData::eventtype type) const; private: // 00030000-78fc-48fe-8e23-433b3a1942d0 - static constexpr ble_uuid128_t BaseUUID() { - return CharUUID(0x00, 0x00); + static constexpr ble_uuid128_t BaseUuid() { + return CharUuid(0x00, 0x00); } // 0003yyxx-78fc-48fe-8e23-433b3a1942d0 - static constexpr ble_uuid128_t CharUUID(uint8_t x, uint8_t y) { + 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}}; } - ble_uuid128_t weatherUUID {BaseUUID()}; + ble_uuid128_t weatherUuid {BaseUuid()}; /** * Just write timeline data here */ - ble_uuid128_t weatherDataCharUUID {CharUUID(0x00, 0x01)}; + ble_uuid128_t weatherDataCharUuid {CharUuid(0x00, 0x01)}; /** * This doesn't take timeline data, * provides some control over it */ - ble_uuid128_t weatherControlCharUUID {CharUUID(0x00, 0x02)}; + ble_uuid128_t weatherControlCharUuid {CharUuid(0x00, 0x02)}; const struct ble_gatt_chr_def characteristicDefinition[3] = { - {.uuid = &weatherDataCharUUID.u, + {.uuid = &weatherDataCharUuid.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE, .val_handle = &eventHandle}, - {.uuid = &weatherControlCharUUID.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, + {.uuid = &weatherControlCharUuid.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, {nullptr}}; const struct ble_gatt_svc_def serviceDefinition[2] = { - {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &weatherUUID.u, .characteristics = characteristicDefinition}, {0}}; + {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &weatherUuid.u, .characteristics = characteristicDefinition}, {0}}; uint16_t eventHandle {}; diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index a1278649..ea96c9f2 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -105,7 +105,6 @@ 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(), nullptr); lv_table_set_col_cnt(infoTask, 3); lv_table_set_row_cnt(infoTask, 8); @@ -118,19 +117,6 @@ std::unique_ptr Weather::CreateScreen4() { lv_table_set_cell_value(infoTask, 0, 2, "Free"); lv_table_set_col_width(infoTask, 2, 90); - auto nb = uxTaskGetSystemState(tasksStatus, 7, nullptr); - std::sort(tasksStatus, tasksStatus + nb, sortById); - for (uint8_t i = 0; i < nb; i++) { - - lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str()); - lv_table_set_cell_value(infoTask, i + 1, 1, tasksStatus[i].pcTaskName); - if (tasksStatus[i].usStackHighWaterMark < 20) { - std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low"; - lv_table_set_cell_value(infoTask, i + 1, 2, str1.c_str()); - } else { - lv_table_set_cell_value(infoTask, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str()); - } - } return std::unique_ptr(new Screens::Label(3, 5, app, infoTask)); } @@ -148,4 +134,4 @@ std::unique_ptr Weather::CreateScreen5() { 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)); -} \ No newline at end of file +} -- 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/components/ble/weather/WeatherService.cpp') 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 900598a7eeff1a84ccf7d0d7c94ac28a780299d4 Mon Sep 17 00:00:00 2001 From: Avamander Date: Sun, 28 Nov 2021 19:13:03 +0200 Subject: Removed versioning because it's not necessary --- src/components/ble/weather/WeatherService.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index bbaa21f0..135f64dd 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -48,18 +48,11 @@ namespace Pinetime { } // Decode QCBORDecodeContext decodeContext; - UsefulBufC encodedCbor; - // TODO: Check, uninit fine? + UsefulBufC encodedCbor = {ctxt->om, OS_MBUF_PKTLEN(ctxt->om)}; QCBORDecode_Init(&decodeContext, encodedCbor, QCBOR_DECODE_MODE_NORMAL); QCBORDecode_EnterMap(&decodeContext, nullptr); // Always encodes to the smallest number of bytes based on the value - int64_t tmpVersion = 0; - QCBORDecode_GetInt64InMapSZ(&decodeContext, "Version", &tmpVersion); - if (tmpVersion != 1) { - // TODO: Return better error? - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } int64_t tmpTimestamp = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); int64_t tmpExpires = 0; -- cgit v1.2.3-70-g09d2 From 48beb7c3b18bcfdc369a63be5923a35a2113aa36 Mon Sep 17 00:00:00 2001 From: Avamander Date: Sun, 28 Nov 2021 20:58:28 +0200 Subject: Improved error handling and fixed incompatibility with co.nstant.in:cbor library --- src/CMakeLists.txt | 10 +++++----- src/components/ble/weather/WeatherService.cpp | 9 ++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cbccb714..9f3b6d4e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -859,7 +859,7 @@ target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_FLOAT_HW_USE) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_PREFERRED_FLOAT) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_EXP_AND_MANTISSA) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) -target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) +#target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_UNCOMMON_TAGS) target_compile_definitions(QCBOR PUBLIC USEFULBUF_CONFIG_LITTLE_ENDIAN) set_target_properties(QCBOR PROPERTIES LINKER_LANGUAGE C) @@ -889,10 +889,10 @@ add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES}) set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME}) target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs QCBOR) target_compile_options(${EXECUTABLE_NAME} PUBLIC - $<$,$>: ${COMMON_FLAGS} -Og -g3> - $<$,$>: ${COMMON_FLAGS} -Os> - $<$,$>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$,$>: ${COMMON_FLAGS} -Os -fno-rtti> + $<$,$>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3> + $<$,$>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os> + $<$,$>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3 -fno-rtti> + $<$,$>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os -fno-rtti> $<$: -MP -MD -x assembler-with-cpp> ) diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 135f64dd..42302610 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -48,13 +48,17 @@ namespace Pinetime { } // Decode QCBORDecodeContext decodeContext; - UsefulBufC encodedCbor = {ctxt->om, OS_MBUF_PKTLEN(ctxt->om)}; + UsefulBufC encodedCbor = {ctxt->om->om_data, OS_MBUF_PKTLEN(ctxt->om)}; QCBORDecode_Init(&decodeContext, encodedCbor, QCBOR_DECODE_MODE_NORMAL); + // KINDLY provide us a fixed-length map QCBORDecode_EnterMap(&decodeContext, nullptr); // 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) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } int64_t tmpExpires = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); if (tmpExpires < 0 || tmpExpires > 4294967295) { @@ -173,8 +177,7 @@ namespace Pinetime { GetTimelineLength(); QCBORDecode_ExitMap(&decodeContext); - auto uErr = QCBORDecode_Finish(&decodeContext); - if (uErr != 0) { + if (QCBORDecode_Finish(&decodeContext) != QCBOR_SUCCESS) { return BLE_ATT_ERR_INSUFFICIENT_RES; } } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { -- 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/components/ble/weather/WeatherService.cpp') 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 From 06b022fc4dd6c2b1e5145e111f5c1f32e4729eab Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 01:15:11 +0200 Subject: Improved UI and fixed a bug --- src/components/ble/weather/WeatherService.cpp | 21 +++++++++++---------- src/displayapp/screens/Weather.cpp | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 10 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 4ec57d00..250b36ab 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -29,6 +29,7 @@ namespace Pinetime { WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController) : system(system), dateTimeController(dateTimeController) { nullHeader = &nullTimelineheader; + nullTimelineheader->timestamp = 0; } void WeatherService::Init() { @@ -211,7 +212,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentObscuration() { @@ -222,7 +223,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentPrecipitation() { @@ -233,7 +234,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentWind() { @@ -244,7 +245,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentTemperature() { @@ -255,7 +256,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentHumidity() { @@ -266,7 +267,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentPressure() { @@ -277,7 +278,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentLocation() { @@ -288,7 +289,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } std::unique_ptr& WeatherService::GetCurrentQuality() { @@ -299,7 +300,7 @@ namespace Pinetime { } } - return reinterpret_cast&>(this->nullHeader); + return reinterpret_cast&>(*this->nullHeader); } size_t WeatherService::GetTimelineLength() const { @@ -330,7 +331,7 @@ namespace Pinetime { timeline.erase(std::remove_if(std::begin(timeline), std::end(timeline), [&](std::unique_ptr const& header) { - return isEventStillValid(header, timeCurrent); + return !isEventStillValid(header, timeCurrent); }), std::end(timeline)); diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 132bee71..0854c74a 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -74,6 +74,16 @@ std::unique_ptr Weather::CreateScreenTemperature() { std::unique_ptr& 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#\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" @@ -97,6 +107,16 @@ std::unique_ptr Weather::CreateScreenAir() { std::unique_ptr& 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" -- cgit v1.2.3-70-g09d2 From 9108952e6ba96f94bbd1530036318c9b21ec0cf9 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 15:18:34 +0200 Subject: Implemented parsing of all defined weather data types --- src/components/ble/weather/WeatherService.cpp | 200 +++++++++++++++++++++++--- 1 file changed, 181 insertions(+), 19 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 250b36ab..c60e0f09 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -42,15 +42,14 @@ 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 uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); + const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) if (packetLen <= 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } // Decode QCBORDecodeContext decodeContext; - UsefulBufC encodedCbor = {ctxt->om->om_data, OS_MBUF_PKTLEN(ctxt->om)}; + UsefulBufC encodedCbor = {ctxt->om->om_data, OS_MBUF_PKTLEN(ctxt->om)}; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) QCBORDecode_Init(&decodeContext, encodedCbor, QCBOR_DECODE_MODE_NORMAL); // KINDLY provide us a fixed-length map @@ -58,18 +57,18 @@ namespace Pinetime { // Always encodes to the smallest number of bytes based on the value int64_t tmpTimestamp = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); - uint8_t err = QCBORDecode_GetError(&decodeContext); - if (err != QCBOR_SUCCESS) { + if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } int64_t tmpExpires = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); - if (tmpExpires < 0 || tmpExpires > 4294967295) { + if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS || tmpExpires < 0 || tmpExpires > 4294967295) { 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)) { + if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS || tmpEventType < 0 || + tmpEventType >= static_cast(WeatherData::eventtype::Length)) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } @@ -79,19 +78,24 @@ namespace Pinetime { airquality->timestamp = tmpTimestamp; airquality->eventType = static_cast(tmpEventType); airquality->expires = tmpExpires; + 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; } airquality->polluter = std::string(static_cast(String.ptr), String.len); + int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); - if (tmpAmount < 0) { + if (tmpAmount < 0 || tmpAmount > 4294967295) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + airquality->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + if (AddEventToTimeline(std::move(airquality))) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - airquality->amount = tmpAmount; - timeline.push_back(std::move(airquality)); break; } case WeatherData::eventtype::Obscuration: { @@ -100,7 +104,23 @@ namespace Pinetime { obscuration->eventType = static_cast(tmpEventType); obscuration->expires = tmpExpires; - timeline.push_back(std::move(obscuration)); + int64_t tmpType = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType); + if (tmpType < 0 || tmpType >= static_cast(WeatherData::obscurationtype::Length)) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + obscuration->type = static_cast(tmpType); + + int64_t tmpAmount = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); + if (tmpAmount < 0 || tmpAmount > 65535) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + obscuration->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + if (AddEventToTimeline(std::move(obscuration))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Precipitation: { @@ -108,7 +128,24 @@ namespace Pinetime { precipitation->timestamp = tmpTimestamp; precipitation->eventType = static_cast(tmpEventType); precipitation->expires = tmpExpires; - timeline.push_back(std::move(precipitation)); + + int64_t tmpType = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType); + if (tmpType < 0 || tmpType >= static_cast(WeatherData::precipitationtype::Length)) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + precipitation->type = static_cast(tmpType); + + int64_t tmpAmount = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); + if (tmpAmount < 0 || tmpAmount > 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + precipitation->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + if (AddEventToTimeline(std::move(precipitation))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Wind: { @@ -116,7 +153,38 @@ namespace Pinetime { wind->timestamp = tmpTimestamp; wind->eventType = static_cast(tmpEventType); wind->expires = tmpExpires; - timeline.push_back(std::move(wind)); + + int64_t tmpMin = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "SpeedMin", &tmpMin); + if (tmpMin < 0 || tmpMin > 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + wind->speedMin = tmpMin; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + int64_t tmpMax = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "SpeedMin", &tmpMax); + if (tmpMax < 0 || tmpMax > 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + wind->speedMax = tmpMax; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + int64_t tmpDMin = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "DirectionMin", &tmpDMin); + if (tmpDMin < 0 || tmpDMin > 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + wind->directionMin = tmpDMin; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + int64_t tmpDMax = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "DirectionMax", &tmpDMax); + if (tmpDMax < 0 || tmpDMax > 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + wind->directionMax = tmpDMax; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + if (AddEventToTimeline(std::move(wind))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Temperature: { @@ -124,7 +192,24 @@ namespace Pinetime { temperature->timestamp = tmpTimestamp; temperature->eventType = static_cast(tmpEventType); temperature->expires = tmpExpires; - timeline.push_back(std::move(temperature)); + + int64_t tmpTemperature = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Temperature", &tmpTemperature); + if (tmpTemperature < 0 || tmpTemperature > 65535) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + temperature->temperature = tmpTemperature; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + int64_t tmpDewPoint = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpDewPoint); + if (tmpDewPoint < 0 || tmpDewPoint > 65535) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + temperature->dewPoint = tmpDewPoint; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + if (AddEventToTimeline(std::move(temperature))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Special: { @@ -132,7 +217,17 @@ namespace Pinetime { special->timestamp = tmpTimestamp; special->eventType = static_cast(tmpEventType); special->expires = tmpExpires; - timeline.push_back(std::move(special)); + + int64_t tmpType = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpType); + if (tmpType < 0 || tmpType >= static_cast(WeatherData::specialtype::Length)) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + special->type = static_cast(tmpType); + + if (AddEventToTimeline(std::move(special))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Pressure: { @@ -140,7 +235,17 @@ namespace Pinetime { pressure->timestamp = tmpTimestamp; pressure->eventType = static_cast(tmpEventType); pressure->expires = tmpExpires; - timeline.push_back(std::move(pressure)); + + int64_t tmpDewPoint = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpDewPoint); + if (tmpDewPoint < 0 || tmpDewPoint >= 65535) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + pressure->pressure = tmpDewPoint; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + + if (AddEventToTimeline(std::move(pressure))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Location: { @@ -148,7 +253,38 @@ namespace Pinetime { location->timestamp = tmpTimestamp; location->eventType = static_cast(tmpEventType); location->expires = tmpExpires; - timeline.push_back(std::move(location)); + + UsefulBufC stringBuf; // TODO: Everything ok with lifecycle here? + QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Location", &stringBuf); + if (UsefulBuf_IsNULLOrEmptyC(stringBuf) != 0) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + location->location = std::string(static_cast(stringBuf.ptr), stringBuf.len); + + int64_t tmpAltitude = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Altitude", &tmpAltitude); + if (tmpAltitude < -32768 || tmpAltitude >= 32767) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + location->altitude = static_cast(tmpAltitude); + + int64_t tmpLatitude = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Latitude", &tmpLatitude); + if (tmpLatitude < -2147483648 || tmpLatitude >= 2147483647) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + location->latitude = static_cast(tmpLatitude); + + int64_t tmpLongitude = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Longitude", &tmpLongitude); + if (tmpLongitude < -2147483648 || tmpLongitude >= 2147483647) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + location->latitude = static_cast(tmpLongitude); + + if (AddEventToTimeline(std::move(location))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Clouds: { @@ -156,7 +292,17 @@ namespace Pinetime { clouds->timestamp = tmpTimestamp; clouds->eventType = static_cast(tmpEventType); clouds->expires = tmpExpires; - timeline.push_back(std::move(clouds)); + + int64_t tmpAmount = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); + if (tmpAmount < 0 || tmpAmount > 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + clouds->amount = static_cast(tmpAmount); + + if (AddEventToTimeline(std::move(clouds))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } case WeatherData::eventtype::Humidity: { @@ -164,7 +310,17 @@ namespace Pinetime { humidity->timestamp = tmpTimestamp; humidity->eventType = static_cast(tmpEventType); humidity->expires = tmpExpires; - timeline.push_back(std::move(humidity)); + + int64_t tmpType = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpType); + if (tmpType < 0 || tmpType >= 255) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + humidity->humidity = static_cast(tmpType); + + if (AddEventToTimeline(std::move(humidity))) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } break; } default: { @@ -183,6 +339,12 @@ namespace Pinetime { // Encode uint8_t buffer[64]; QCBOREncodeContext encodeContext; + /* TODO: This is very much still a test endpoint + * it needs a characteristic UUID check + * and actual implementations that show + * what actually has to be read. + * WARN: Consider commands not part of the API for now! + */ QCBOREncode_Init(&encodeContext, UsefulBuf_FROM_BYTE_ARRAY(buffer)); QCBOREncode_OpenMap(&encodeContext); QCBOREncode_AddTextToMap(&encodeContext, "test", UsefulBuf_FROM_SZ_LITERAL("test")); -- cgit v1.2.3-70-g09d2 From 75cf5324baf760b3f463ba84126c317471266b32 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 18:41:01 +0200 Subject: Fixed an incorrect decode in Humidity --- src/components/ble/weather/WeatherService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index c60e0f09..c2a1cec0 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -312,7 +312,7 @@ namespace Pinetime { humidity->expires = tmpExpires; int64_t tmpType = 0; - QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpType); + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Humidity", &tmpType); if (tmpType < 0 || tmpType >= 255) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } -- cgit v1.2.3-70-g09d2 From ffd6c3f0953c753b0caf151be1eb824bdd777264 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 21:11:31 +0200 Subject: Removed an instance of shadowing --- src/components/ble/weather/WeatherService.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index c2a1cec0..e6d22d71 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -79,12 +79,12 @@ namespace Pinetime { airquality->eventType = static_cast(tmpEventType); airquality->expires = tmpExpires; - UsefulBufC String; // TODO: Everything ok with lifecycle here? - QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &String); - if (UsefulBuf_IsNULLOrEmptyC(String) != 0) { + UsefulBufC stringBuf; // TODO: Everything ok with lifecycle here? + QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &stringBuf); + if (UsefulBuf_IsNULLOrEmptyC(stringBuf) != 0) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - airquality->polluter = std::string(static_cast(String.ptr), String.len); + airquality->polluter = std::string(static_cast(stringBuf.ptr), stringBuf.len); int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); -- cgit v1.2.3-70-g09d2 From 154e3d27ad0053edf09db6437264028cbca8afd1 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 23:45:01 +0200 Subject: Added a few helper functions --- src/components/ble/weather/WeatherService.cpp | 46 +++++++++++++++++++++++++++ src/components/ble/weather/WeatherService.h | 17 +++++++--- 2 files changed, 59 insertions(+), 4 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index e6d22d71..c8eb3c20 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -513,5 +513,51 @@ namespace Pinetime { uint64_t WeatherService::GetCurrentUnixTimestamp() const { return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); } + + int16_t WeatherService::getTodayMinTemp() const { + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - + ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + int16_t result = -32768; + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp) && + header->timestamp < currentDayEnd && + reinterpret_cast&>(header)->temperature != -32768) { + int16_t temperature = reinterpret_cast&>(header)->temperature; + if (result == -32768) { + result = temperature; + } else if (result > temperature) { + result = temperature; + } else { + // The temperature in this item is higher than the lowest we've found + } + } + } + + return result; + } + + int16_t WeatherService::getTodayMaxTemp() const { + uint64_t currentTimestamp = GetCurrentUnixTimestamp(); + uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - + ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + int16_t result = -32768; + for (auto&& header : this->timeline) { + if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp) && + header->timestamp < currentDayEnd && + reinterpret_cast&>(header)->temperature != -32768) { + int16_t temperature = reinterpret_cast&>(header)->temperature; + if (result == -32768) { + result = temperature; + } else if (result < temperature) { + result = temperature; + } else { + // The temperature in this item is lower than the highest we've found + } + } + } + + return result; + } } } diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index cc1a4b0d..52b0356a 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -61,6 +61,17 @@ namespace Pinetime { std::unique_ptr& GetCurrentPressure(); std::unique_ptr& GetCurrentQuality(); + /** + * Searches for the current day's maximum temperature + * @return -32768 if there's no data, degrees celcius times 100 otherwise + */ + int16_t getTodayMaxTemp() const; + /** + * Searches for the current day's minimum temperature + * @return -32768 if there's no data, degrees celcius times 100 otherwise + */ + int16_t getTodayMinTemp() const; + /* * Management functions */ @@ -75,7 +86,6 @@ namespace Pinetime { size_t GetTimelineLength() const; /** * Checks if an event of a certain type exists in the timeline - * @return */ bool HasTimelineEventOfType(WeatherData::eventtype type) const; @@ -124,6 +134,8 @@ namespace Pinetime { Pinetime::Controllers::DateTime& dateTimeController; std::vector> timeline; + std::unique_ptr nullTimelineheader = std::make_unique(); + std::unique_ptr* nullHeader; /** * Cleans up the timeline of expired events @@ -149,9 +161,6 @@ namespace Pinetime { * @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; }; } } -- cgit v1.2.3-70-g09d2 From be7931c4fb304df077f8a795d1e6e94c522556f7 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 1 Dec 2021 23:47:54 +0200 Subject: Whoops, fixed a wrong type --- src/components/ble/weather/WeatherService.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index c8eb3c20..c342602e 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -520,7 +520,7 @@ namespace Pinetime { ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp) && header->timestamp < currentDayEnd && reinterpret_cast&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast&>(header)->temperature; @@ -543,7 +543,7 @@ namespace Pinetime { ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp) && header->timestamp < currentDayEnd && reinterpret_cast&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast&>(header)->temperature; -- cgit v1.2.3-70-g09d2 From 4a8f72bd1e77a387b1fe97d316c0f75d8c94c936 Mon Sep 17 00:00:00 2001 From: Avamander Date: Thu, 2 Dec 2021 21:12:33 +0200 Subject: Fixed a bug in DewPoint decoding --- src/components/ble/weather/WeatherService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index c342602e..e5d8053a 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -202,7 +202,7 @@ namespace Pinetime { int64_t tmpDewPoint = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpDewPoint); - if (tmpDewPoint < 0 || tmpDewPoint > 65535) { + if (tmpDewPoint < -32768 || tmpDewPoint > 32767) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } temperature->dewPoint = tmpDewPoint; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) -- cgit v1.2.3-70-g09d2 From 58d454b11fe3c143b37aea90772c122321a5b902 Mon Sep 17 00:00:00 2001 From: Avamander Date: Thu, 2 Dec 2021 23:49:51 +0200 Subject: Improved Temperature parsing --- src/components/ble/weather/WeatherService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index e5d8053a..a30b2270 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -195,7 +195,7 @@ namespace Pinetime { int64_t tmpTemperature = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Temperature", &tmpTemperature); - if (tmpTemperature < 0 || tmpTemperature > 65535) { + if (tmpTemperature < -32768 || tmpTemperature > 32767) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } temperature->temperature = tmpTemperature; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) -- cgit v1.2.3-70-g09d2 From 62bb6b51634b22410a96f1ca9cbe183d1e9c504c Mon Sep 17 00:00:00 2001 From: Avamander Date: Fri, 3 Dec 2021 16:28:17 +0200 Subject: Better cleanup, bugfixes and improvements in weather parsing. UI improvements --- src/components/ble/weather/WeatherService.cpp | 107 ++++++++++++++++++-------- src/components/ble/weather/WeatherService.h | 7 +- src/displayapp/DisplayApp.cpp | 7 +- src/displayapp/screens/Weather.cpp | 8 +- 4 files changed, 89 insertions(+), 40 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index a30b2270..f3be35f2 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -58,17 +58,20 @@ namespace Pinetime { int64_t tmpTimestamp = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } int64_t tmpExpires = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS || tmpExpires < 0 || tmpExpires > 4294967295) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } int64_t tmpEventType = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", &tmpEventType); if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS || tmpEventType < 0 || tmpEventType >= static_cast(WeatherData::eventtype::Length)) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } @@ -82,6 +85,7 @@ namespace Pinetime { UsefulBufC stringBuf; // TODO: Everything ok with lifecycle here? QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &stringBuf); if (UsefulBuf_IsNULLOrEmptyC(stringBuf) != 0) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } airquality->polluter = std::string(static_cast(stringBuf.ptr), stringBuf.len); @@ -89,11 +93,13 @@ namespace Pinetime { int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); if (tmpAmount < 0 || tmpAmount > 4294967295) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } airquality->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) - if (AddEventToTimeline(std::move(airquality))) { + if (!AddEventToTimeline(std::move(airquality))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -107,6 +113,7 @@ namespace Pinetime { int64_t tmpType = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType); if (tmpType < 0 || tmpType >= static_cast(WeatherData::obscurationtype::Length)) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } obscuration->type = static_cast(tmpType); @@ -114,11 +121,13 @@ namespace Pinetime { int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); if (tmpAmount < 0 || tmpAmount > 65535) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } obscuration->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) - if (AddEventToTimeline(std::move(obscuration))) { + if (!AddEventToTimeline(std::move(obscuration))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -132,6 +141,7 @@ namespace Pinetime { int64_t tmpType = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType); if (tmpType < 0 || tmpType >= static_cast(WeatherData::precipitationtype::Length)) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } precipitation->type = static_cast(tmpType); @@ -139,11 +149,13 @@ namespace Pinetime { int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); if (tmpAmount < 0 || tmpAmount > 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } precipitation->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) - if (AddEventToTimeline(std::move(precipitation))) { + if (!AddEventToTimeline(std::move(precipitation))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -157,6 +169,7 @@ namespace Pinetime { int64_t tmpMin = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "SpeedMin", &tmpMin); if (tmpMin < 0 || tmpMin > 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } wind->speedMin = tmpMin; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) @@ -164,6 +177,7 @@ namespace Pinetime { int64_t tmpMax = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "SpeedMin", &tmpMax); if (tmpMax < 0 || tmpMax > 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } wind->speedMax = tmpMax; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) @@ -171,6 +185,7 @@ namespace Pinetime { int64_t tmpDMin = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "DirectionMin", &tmpDMin); if (tmpDMin < 0 || tmpDMin > 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } wind->directionMin = tmpDMin; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) @@ -178,11 +193,13 @@ namespace Pinetime { int64_t tmpDMax = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "DirectionMax", &tmpDMax); if (tmpDMax < 0 || tmpDMax > 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } wind->directionMax = tmpDMax; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) - if (AddEventToTimeline(std::move(wind))) { + if (!AddEventToTimeline(std::move(wind))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -196,18 +213,23 @@ namespace Pinetime { int64_t tmpTemperature = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Temperature", &tmpTemperature); if (tmpTemperature < -32768 || tmpTemperature > 32767) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - temperature->temperature = tmpTemperature; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + temperature->temperature = + static_cast(tmpTemperature); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) int64_t tmpDewPoint = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpDewPoint); if (tmpDewPoint < -32768 || tmpDewPoint > 32767) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - temperature->dewPoint = tmpDewPoint; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + temperature->dewPoint = + static_cast(tmpDewPoint); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) - if (AddEventToTimeline(std::move(temperature))) { + if (!AddEventToTimeline(std::move(temperature))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -219,13 +241,15 @@ namespace Pinetime { special->expires = tmpExpires; int64_t tmpType = 0; - QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpType); + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType); if (tmpType < 0 || tmpType >= static_cast(WeatherData::specialtype::Length)) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } special->type = static_cast(tmpType); - if (AddEventToTimeline(std::move(special))) { + if (!AddEventToTimeline(std::move(special))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -236,14 +260,16 @@ namespace Pinetime { pressure->eventType = static_cast(tmpEventType); pressure->expires = tmpExpires; - int64_t tmpDewPoint = 0; - QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpDewPoint); - if (tmpDewPoint < 0 || tmpDewPoint >= 65535) { + int64_t tmpPressure = 0; + QCBORDecode_GetInt64InMapSZ(&decodeContext, "Pressure", &tmpPressure); + if (tmpPressure < 0 || tmpPressure >= 65535) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - pressure->pressure = tmpDewPoint; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + pressure->pressure = tmpPressure; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) - if (AddEventToTimeline(std::move(pressure))) { + if (!AddEventToTimeline(std::move(pressure))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -257,6 +283,7 @@ namespace Pinetime { UsefulBufC stringBuf; // TODO: Everything ok with lifecycle here? QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Location", &stringBuf); if (UsefulBuf_IsNULLOrEmptyC(stringBuf) != 0) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } location->location = std::string(static_cast(stringBuf.ptr), stringBuf.len); @@ -264,6 +291,7 @@ namespace Pinetime { int64_t tmpAltitude = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Altitude", &tmpAltitude); if (tmpAltitude < -32768 || tmpAltitude >= 32767) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } location->altitude = static_cast(tmpAltitude); @@ -271,6 +299,7 @@ namespace Pinetime { int64_t tmpLatitude = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Latitude", &tmpLatitude); if (tmpLatitude < -2147483648 || tmpLatitude >= 2147483647) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } location->latitude = static_cast(tmpLatitude); @@ -278,11 +307,13 @@ namespace Pinetime { int64_t tmpLongitude = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Longitude", &tmpLongitude); if (tmpLongitude < -2147483648 || tmpLongitude >= 2147483647) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } location->latitude = static_cast(tmpLongitude); - if (AddEventToTimeline(std::move(location))) { + if (!AddEventToTimeline(std::move(location))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -296,11 +327,13 @@ namespace Pinetime { int64_t tmpAmount = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount); if (tmpAmount < 0 || tmpAmount > 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } clouds->amount = static_cast(tmpAmount); - if (AddEventToTimeline(std::move(clouds))) { + if (!AddEventToTimeline(std::move(clouds))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; @@ -314,17 +347,20 @@ namespace Pinetime { int64_t tmpType = 0; QCBORDecode_GetInt64InMapSZ(&decodeContext, "Humidity", &tmpType); if (tmpType < 0 || tmpType >= 255) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } humidity->humidity = static_cast(tmpType); - if (AddEventToTimeline(std::move(humidity))) { + if (!AddEventToTimeline(std::move(humidity))) { + CleanUpQcbor(&decodeContext); return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } break; } default: { - break; + CleanUpQcbor(&decodeContext); + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } } @@ -369,7 +405,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentClouds() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Clouds && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Clouds && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -380,7 +416,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentObscuration() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Obscuration && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Obscuration && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -391,7 +427,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentPrecipitation() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Precipitation && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Precipitation && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -402,7 +438,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentWind() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Wind && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Wind && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -413,7 +449,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentTemperature() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -424,7 +460,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentHumidity() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Humidity && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Humidity && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -435,7 +471,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentPressure() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Pressure && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Pressure && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -446,7 +482,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentLocation() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Location && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::Location && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -457,7 +493,7 @@ namespace Pinetime { std::unique_ptr& WeatherService::GetCurrentQuality() { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == WeatherData::eventtype::AirQuality && IsEventStillValid(header, currentTimestamp)) { return reinterpret_cast&>(header); } } @@ -481,7 +517,7 @@ namespace Pinetime { bool WeatherService::HasTimelineEventOfType(const WeatherData::eventtype type) const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); for (auto&& header : timeline) { - if (header->eventType == type && isEventStillValid(header, currentTimestamp)) { + if (header->eventType == type && IsEventStillValid(header, currentTimestamp)) { return true; } } @@ -493,7 +529,7 @@ namespace Pinetime { timeline.erase(std::remove_if(std::begin(timeline), std::end(timeline), [&](std::unique_ptr const& header) { - return !isEventStillValid(header, timeCurrent); + return !IsEventStillValid(header, timeCurrent); }), std::end(timeline)); @@ -505,9 +541,9 @@ namespace Pinetime { return first->timestamp > second->timestamp; } - bool WeatherService::isEventStillValid(const std::unique_ptr& header, const uint64_t currentTimestamp) { + bool WeatherService::IsEventStillValid(const std::unique_ptr& uniquePtr, const uint64_t timestamp) { // Not getting timestamp in isEventStillValid for more speed - return header->timestamp + header->expires <= currentTimestamp; + return uniquePtr->timestamp + uniquePtr->expires >= timestamp; } uint64_t WeatherService::GetCurrentUnixTimestamp() const { @@ -520,7 +556,7 @@ namespace Pinetime { ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && header->timestamp < currentDayEnd && reinterpret_cast&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast&>(header)->temperature; @@ -543,7 +579,7 @@ namespace Pinetime { ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && header->timestamp < currentDayEnd && reinterpret_cast&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast&>(header)->temperature; @@ -559,5 +595,10 @@ namespace Pinetime { return result; } + + void WeatherService::CleanUpQcbor(QCBORDecodeContext* decodeContext) { + QCBORDecode_ExitMap(decodeContext); + QCBORDecode_Finish(decodeContext); + } } } diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index 52b0356a..a9f02b16 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -30,7 +30,8 @@ #undef min #include "WeatherData.h" -#include +#include "libs/QCBOR/inc/qcbor/qcbor.h" +#include "components/datetime/DateTimeController.h" int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg); @@ -160,7 +161,9 @@ namespace Pinetime { * @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); + static bool IsEventStillValid(const std::unique_ptr& uniquePtr, const uint64_t timestamp); + + void CleanUpQcbor(QCBORDecodeContext* decodeContext); }; } } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 80155187..d45251b9 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -1,5 +1,6 @@ #include "displayapp/DisplayApp.h" #include +#include #include "displayapp/screens/HeartRate.h" #include "displayapp/screens/Motion.h" #include "displayapp/screens/Timer.h" @@ -439,7 +440,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) currentScreen = std::make_unique(this, systemTask->nimble().music()); break; case Apps::Navigation: - currentScreen = std::make_unique(this, systemTask->nimble().navigation()); + currentScreen = std::make_unique(this, systemTask->nimble().weather()); + // currentScreen = std::make_unique(this, systemTask->nimble().navigation()); break; case Apps::HeartRate: currentScreen = std::make_unique(this, heartRateController, *systemTask); @@ -451,6 +453,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Motion: currentScreen = std::make_unique(this, motionController); break; + case Apps::Weather: + currentScreen = std::make_unique(this, systemTask->nimble().weather()); + break; case Apps::Steps: currentScreen = std::make_unique(this, motionController, settingsController); break; diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index c9852ee1..d4241194 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -76,22 +76,22 @@ std::unique_ptr Weather::CreateScreenTemperature() { // Do not use the data, it's invalid lv_label_set_text_fmt(label, "#FFFF00 Temperature#\n\n" - "#444444 %d#\n\n" + "#444444 %.2f#°C \n\n" "#444444 %d#\n\n" "%d\n" "%d\n", - 0, + 0.0f, 0, 0, 0); } else { lv_label_set_text_fmt(label, "#FFFF00 Temperature#\n\n" - "#444444 %hd%%#°C \n\n" + "#444444 %.2f#°C \n\n" "#444444 %hd#\n\n" "%llu\n" "%lu\n", - current->temperature, + current->temperature / 100.0f, current->dewPoint, current->timestamp, current->expires); -- cgit v1.2.3-70-g09d2 From 3eebe66d659c9c8e72a7c355973c74c2b8899174 Mon Sep 17 00:00:00 2001 From: Avamander Date: Sat, 4 Dec 2021 17:12:34 +0200 Subject: Updated docs and renamed functions for consistency --- doc/ble.md | 18 +++++++++++------- src/components/ble/weather/WeatherService.cpp | 4 ++-- src/components/ble/weather/WeatherService.h | 11 +++++++---- 3 files changed, 20 insertions(+), 13 deletions(-) (limited to 'src/components/ble/weather/WeatherService.cpp') diff --git a/doc/ble.md b/doc/ble.md index 8573166f..2b86243e 100644 --- a/doc/ble.md +++ b/doc/ble.md @@ -2,7 +2,7 @@ ## Introduction This page describes the BLE implementation and API built in this firmware. -**Note** : I'm a beginner in BLE related technologies and the information in this document reflects my current knowledge and understanding of the BLE stack. This information might be erroneous or incomplete. Feel free to submit a PR if you think you can improve it. +**Note**: I'm a beginner in BLE related technologies and the information in this document reflects my current knowledge and understanding of the BLE stack. This information might be erroneous or incomplete. Feel free to submit a PR if you think you can improve it. --- @@ -72,12 +72,16 @@ The following custom services are implemented in InfiniTime: * [Navigation Service](NavigationService.md) : 00010000-78fc-48fe-8e23-433b3a1942d0 - - Since InfiniTime 0.13 - * Call characteristic (extension to the Alert Notification Service): 00020001-78fc-48fe-8e23-433b3a1942d0 - - - - Since InfiniTime 1.7: - * [Motion Service](MotionService.md) : 00030000-78fc-48fe-8e23-433b3a1942d0 +- Since InfiniTime 0.13 + * Call characteristic (extension to the Alert Notification Service): 00020001-78fc-48fe-8e23-433b3a1942d0 + + +- Since InfiniTime 1.7: + * [Motion Service](MotionService.md): 00030000-78fc-48fe-8e23-433b3a1942d0 + + +- Since InfiniTime 1.8: + * [Weather Service](/src/components/ble/weather/WeatherService.h): 00040000-78fc-48fe-8e23-433b3a1942d0 --- diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index f3be35f2..23f53b74 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -550,7 +550,7 @@ namespace Pinetime { return std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()).count(); } - int16_t WeatherService::getTodayMinTemp() const { + int16_t WeatherService::GetTodayMinTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); @@ -573,7 +573,7 @@ namespace Pinetime { return result; } - int16_t WeatherService::getTodayMaxTemp() const { + int16_t WeatherService::GetTodayMaxTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index a9f02b16..eca70cbd 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -64,14 +64,14 @@ namespace Pinetime { /** * Searches for the current day's maximum temperature - * @return -32768 if there's no data, degrees celcius times 100 otherwise + * @return -32768 if there's no data, degrees Celsius times 100 otherwise */ - int16_t getTodayMaxTemp() const; + int16_t GetTodayMaxTemp() const; /** * Searches for the current day's minimum temperature - * @return -32768 if there's no data, degrees celcius times 100 otherwise + * @return -32768 if there's no data, degrees Celsius times 100 otherwise */ - int16_t getTodayMinTemp() const; + int16_t GetTodayMinTemp() const; /* * Management functions @@ -163,6 +163,9 @@ namespace Pinetime { */ static bool IsEventStillValid(const std::unique_ptr& uniquePtr, const uint64_t timestamp); + /** + * This is a helper function that closes a QCBOR map and decoding context cleanly + */ void CleanUpQcbor(QCBORDecodeContext* decodeContext); }; } -- cgit v1.2.3-70-g09d2