/* 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 . */ #pragma once #include #include #include #include #define min // workaround: nimble's min/max macros conflict with libstdc++ #define max #include #include #undef max #undef min #include "WeatherData.h" #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); namespace Pinetime { namespace System { class SystemTask; } namespace Controllers { class WeatherService { public: explicit WeatherService(System::SystemTask& system, DateTime& dateTimeController); void Init(); int OnCommand(struct ble_gatt_access_ctxt* ctxt); /* * Helper functions for quick access to currently valid data */ 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(); /** * Searches for the current day's maximum temperature * @return -32768 if there's no data, degrees Celsius times 100 otherwise */ int16_t GetTodayMaxTemp() const; /** * Searches for the current day's minimum temperature * @return -32768 if there's no data, degrees Celsius times 100 otherwise */ int16_t GetTodayMinTemp() const; /* * Management functions */ /** * Adds an event to the timeline * @return */ bool AddEventToTimeline(std::unique_ptr event); /** * Gets the current timeline length */ size_t GetTimelineLength() const; /** * Checks if an event of a certain type exists in the timeline */ bool HasTimelineEventOfType(WeatherData::eventtype type) const; private: // 00040000-78fc-48fe-8e23-433b3a1942d0 static constexpr ble_uuid128_t BaseUuid() { return CharUuid(0x00, 0x00); } // 0004yyxx-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, y, x, 0x04, 0x00}}; } ble_uuid128_t weatherUuid {BaseUuid()}; /** * Just write timeline data here. * * See {@link WeatherData.h} for more information. */ ble_uuid128_t weatherDataCharUuid {CharUuid(0x00, 0x01)}; /** * This doesn't take timeline data, provides some control over it. * * NOTE: Currently not supported. Companion app implementer feedback required. * There's very little point in solidifying an API before we know the needs. */ 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}}; uint16_t eventHandle {}; Pinetime::System::SystemTask& system; 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 */ void TidyTimeline(); /** * Compares two timeline events */ static bool CompareTimelineEvents(const std::unique_ptr& first, const std::unique_ptr& second); /** * 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); /** * This is a helper function that closes a QCBOR map and decoding context cleanly */ void CleanUpQcbor(QCBORDecodeContext* decodeContext); }; } }