summaryrefslogtreecommitdiff
path: root/src/components/ble/weather
diff options
context:
space:
mode:
authorAvamander <avamander@gmail.com>2021-06-16 23:31:17 +0300
committerAvamander <avamander@gmail.com>2021-12-04 22:03:40 +0200
commit6e165848161b72d1afa43af6807c654d3fc23d03 (patch)
treef188c90a2fe9c5d3419617cb25786f3c74c6c54d /src/components/ble/weather
parenteb27813c1839ff2edcce3176e11b1258167af229 (diff)
Skeleton of the receiving logic
Diffstat (limited to 'src/components/ble/weather')
-rw-r--r--src/components/ble/weather/WeatherData.h37
-rw-r--r--src/components/ble/weather/WeatherService.cpp139
-rw-r--r--src/components/ble/weather/WeatherService.h45
3 files changed, 145 insertions, 76 deletions
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<int64_t*>(&(timelineHeader.timestamp)));
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", reinterpret_cast<int64_t*>(&(timelineHeader.expires)));
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", reinterpret_cast<int64_t*>(&(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<int64_t>(WeatherData::eventtype::Length)) {
+ // TODO: Return better error?
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+
+ switch (static_cast<WeatherData::eventtype>(tmpEventType)) {
+ // TODO: Populate
case WeatherData::eventtype::AirQuality: {
+ std::unique_ptr<WeatherData::AirQuality> airquality = std::make_unique<WeatherData::AirQuality>();
+ airquality->timestamp = tmpTimestamp;
+ airquality->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ airquality->expires = tmpExpires;
+
+ timeline.push_back(std::move(airquality));
break;
}
case WeatherData::eventtype::Obscuration: {
+ std::unique_ptr<WeatherData::Obscuration> obscuration = std::make_unique<WeatherData::Obscuration>();
+ obscuration->timestamp = tmpTimestamp;
+ obscuration->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ obscuration->expires = tmpExpires;
+
+ timeline.push_back(std::move(obscuration));
break;
}
case WeatherData::eventtype::Precipitation: {
+ std::unique_ptr<WeatherData::Precipitation> precipitation = std::make_unique<WeatherData::Precipitation>();
+ precipitation->timestamp = tmpTimestamp;
+ precipitation->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ precipitation->expires = tmpExpires;
+ timeline.push_back(std::move(precipitation));
break;
}
case WeatherData::eventtype::Wind: {
+ std::unique_ptr<WeatherData::Wind> wind = std::make_unique<WeatherData::Wind>();
+ wind->timestamp = tmpTimestamp;
+ wind->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ wind->expires = tmpExpires;
+ timeline.push_back(std::move(wind));
break;
}
case WeatherData::eventtype::Temperature: {
+ std::unique_ptr<WeatherData::Temperature> temperature = std::make_unique<WeatherData::Temperature>();
+ temperature->timestamp = tmpTimestamp;
+ temperature->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ temperature->expires = tmpExpires;
+ timeline.push_back(std::move(temperature));
break;
}
case WeatherData::eventtype::Special: {
+ std::unique_ptr<WeatherData::Special> special = std::make_unique<WeatherData::Special>();
+ special->timestamp = tmpTimestamp;
+ special->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ special->expires = tmpExpires;
+ timeline.push_back(std::move(special));
break;
}
case WeatherData::eventtype::Pressure: {
+ std::unique_ptr<WeatherData::Pressure> pressure = std::make_unique<WeatherData::Pressure>();
+ pressure->timestamp = tmpTimestamp;
+ pressure->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ pressure->expires = tmpExpires;
+ timeline.push_back(std::move(pressure));
break;
}
case WeatherData::eventtype::Location: {
+ std::unique_ptr<WeatherData::Location> location = std::make_unique<WeatherData::Location>();
+ location->timestamp = tmpTimestamp;
+ location->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
+ location->expires = tmpExpires;
+ timeline.push_back(std::move(location));
break;
}
case WeatherData::eventtype::Clouds: {
+ std::unique_ptr<WeatherData::Clouds> clouds = std::make_unique<WeatherData::Clouds>();
+ clouds->timestamp = tmpTimestamp;
+ clouds->eventType = static_cast<WeatherData::eventtype>(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<WeatherData::timelineheader> event) {
+ bool WeatherService::addEventToTimeline(std::unique_ptr<WeatherData::TimelineHeader> 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<WeatherData::timelineheader> const& header) {
+ [&](std::unique_ptr<WeatherData::TimelineHeader> 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<WeatherData::timelineheader>& first,
- const std::unique_ptr<WeatherData::timelineheader>& second) {
+ bool WeatherService::compareTimelineEvents(const std::unique_ptr<WeatherData::TimelineHeader>& first,
+ const std::unique_ptr<WeatherData::TimelineHeader>& 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<WeatherData::timelineheader> event);
+ bool addEventToTimeline(std::unique_ptr<WeatherData::TimelineHeader> 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<ble_uuid_t*>(&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<ble_uuid_t*>(&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<ble_uuid_t*>(&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<std::unique_ptr<WeatherData::timelineheader>> timeline;
+ std::vector<std::unique_ptr<WeatherData::TimelineHeader>> 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<WeatherData::timelineheader>& first,
- const std::unique_ptr<WeatherData::timelineheader>& second);
+ static bool compareTimelineEvents(const std::unique_ptr<WeatherData::TimelineHeader>& first,
+ const std::unique_ptr<WeatherData::TimelineHeader>& second);
/**
- *
+ * Returns current UNIX timestamp
*/
uint64_t getCurrentUNIXTimestamp() const;
};