summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/ble/CurrentTimeClient.cpp20
-rw-r--r--src/components/ble/CurrentTimeClient.h10
-rw-r--r--src/components/ble/CurrentTimeService.cpp99
-rw-r--r--src/components/ble/CurrentTimeService.h27
-rw-r--r--src/components/datetime/DateTimeController.cpp6
-rw-r--r--src/components/datetime/DateTimeController.h53
6 files changed, 160 insertions, 55 deletions
diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp
index 53e98cb6..96134526 100644
--- a/src/components/ble/CurrentTimeClient.cpp
+++ b/src/components/ble/CurrentTimeClient.cpp
@@ -85,21 +85,11 @@ int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_g
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
CtsData result;
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
- NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d",
- result.year,
- result.month,
- result.dayofmonth,
- result.hour,
- result.minute,
- result.second);
- dateTimeController.SetTime(result.year,
- result.month,
- result.dayofmonth,
- 0,
- result.hour,
- result.minute,
- result.second,
- nrf_rtc_counter_get(portNRF_RTC_REG));
+ uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO;
+
+ NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
+ dateTimeController
+ .SetTime(year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
} else {
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
}
diff --git a/src/components/ble/CurrentTimeClient.h b/src/components/ble/CurrentTimeClient.h
index 9e48be79..c718d2d9 100644
--- a/src/components/ble/CurrentTimeClient.h
+++ b/src/components/ble/CurrentTimeClient.h
@@ -29,14 +29,16 @@ namespace Pinetime {
private:
typedef struct __attribute__((packed)) {
- uint16_t year;
+ uint8_t year_LSO; // explicit byte ordering to be independent of machine order
+ uint8_t year_MSO; // BLE GATT is little endian
uint8_t month;
uint8_t dayofmonth;
uint8_t hour;
uint8_t minute;
uint8_t second;
- uint8_t millis;
- uint8_t reason;
+ uint8_t dayofweek;
+ uint8_t fractions256; // currently ignored
+ uint8_t reason; // currently ignored, not that any host would set it anyway
} CtsData;
static constexpr uint16_t ctsServiceId {0x1805};
@@ -55,4 +57,4 @@ namespace Pinetime {
std::function<void(uint16_t)> onServiceDiscovered;
};
}
-} \ No newline at end of file
+}
diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp
index 8430d1bc..a264efba 100644
--- a/src/components/ble/CurrentTimeService.cpp
+++ b/src/components/ble/CurrentTimeService.cpp
@@ -5,11 +5,23 @@
using namespace Pinetime::Controllers;
constexpr ble_uuid16_t CurrentTimeService::ctsUuid;
-constexpr ble_uuid16_t CurrentTimeService::ctChrUuid;
+constexpr ble_uuid16_t CurrentTimeService::ctsCtChrUuid;
+constexpr ble_uuid16_t CurrentTimeService::ctsLtChrUuid;
int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
auto cts = static_cast<CurrentTimeService*>(arg);
- return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt);
+
+ return cts->OnCurrentTimeServiceAccessed(conn_handle, attr_handle, ctxt);
+}
+
+int CurrentTimeService::OnCurrentTimeServiceAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
+ switch (ble_uuid_u16(ctxt->chr->uuid)) {
+ case ctsCurrentTimeCharId:
+ return OnCurrentTimeAccessed(conn_handle, attr_handle, ctxt);
+ case ctsLocalTimeCharId:
+ return OnLocalTimeAccessed(conn_handle, attr_handle, ctxt);
+ }
+ return -1; // Unknown characteristic
}
void CurrentTimeService::Init() {
@@ -18,45 +30,69 @@ void CurrentTimeService::Init() {
ASSERT(res == 0);
res = ble_gatts_add_svcs(serviceDefinition);
+
ASSERT(res == 0);
}
-int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
+int CurrentTimeService::OnCurrentTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
NRF_LOG_INFO("Setting time...");
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
- CtsData result;
- os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
-
- NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d",
- result.year,
- result.month,
- result.dayofmonth,
- result.hour,
- result.minute,
- result.second);
-
- m_dateTimeController.SetTime(result.year,
- result.month,
- result.dayofmonth,
- 0,
- result.hour,
- result.minute,
- result.second,
- nrf_rtc_counter_get(portNRF_RTC_REG));
+ CtsCurrentTimeData result;
+ int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsCurrentTimeData), &result);
+ if (res < 0) {
+ NRF_LOG_ERROR("Error reading BLE Data writing to CTS Current Time (too little data)")
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+
+ uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO;
+
+ NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
+
+ m_dateTimeController
+ .SetTime(year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
- CtsData currentDateTime;
- currentDateTime.year = m_dateTimeController.Year();
+ CtsCurrentTimeData currentDateTime;
+ currentDateTime.year_LSO = m_dateTimeController.Year() & 0xff;
+ currentDateTime.year_MSO = (m_dateTimeController.Year() >> 8) & 0xff;
currentDateTime.month = static_cast<u_int8_t>(m_dateTimeController.Month());
currentDateTime.dayofmonth = m_dateTimeController.Day();
currentDateTime.hour = m_dateTimeController.Hours();
currentDateTime.minute = m_dateTimeController.Minutes();
currentDateTime.second = m_dateTimeController.Seconds();
- currentDateTime.millis = 0;
+ currentDateTime.fractions256 = 0;
- int res = os_mbuf_append(ctxt->om, &currentDateTime, sizeof(CtsData));
+ int res = os_mbuf_append(ctxt->om, &currentDateTime, sizeof(CtsCurrentTimeData));
+ return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+
+ return 0;
+}
+
+int CurrentTimeService::OnLocalTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
+ NRF_LOG_INFO("Setting timezone...");
+
+ if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+ CtsLocalTimeData result;
+ int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsLocalTimeData), &result);
+
+ if (res < 0) {
+ NRF_LOG_ERROR("Error reading BLE Data writing to CTS Local Time (too little data)")
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+
+ NRF_LOG_INFO("Received data: %d %d", result.timezone, result.dst);
+
+ m_dateTimeController.SetTimeZone(result.timezone, result.dst);
+
+ } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
+ CtsLocalTimeData currentTimezone;
+ currentTimezone.timezone = m_dateTimeController.TzOffset();
+ currentTimezone.dst = m_dateTimeController.DstOffset();
+
+ int res = os_mbuf_append(ctxt->om, &currentTimezone, sizeof(currentTimezone));
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
@@ -64,12 +100,19 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
}
CurrentTimeService::CurrentTimeService(DateTime& dateTimeController)
- : characteristicDefinition {{.uuid = &ctChrUuid.u,
+ : characteristicDefinition {
+
+ {.uuid = &ctsLtChrUuid.u,
.access_cb = CTSCallback,
+ .arg = this,
+ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ},
+ {.uuid = &ctsCtChrUuid.u,
+ .access_cb = CTSCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ},
- {0}},
+
+ {0}},
serviceDefinition {
{/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
diff --git a/src/components/ble/CurrentTimeService.h b/src/components/ble/CurrentTimeService.h
index ca87d970..91544314 100644
--- a/src/components/ble/CurrentTimeService.h
+++ b/src/components/ble/CurrentTimeService.h
@@ -16,29 +16,40 @@ namespace Pinetime {
CurrentTimeService(DateTime& dateTimeController);
void Init();
- int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
+ int OnCurrentTimeServiceAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
+ int OnCurrentTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
+ int OnLocalTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
private:
static constexpr uint16_t ctsId {0x1805};
- static constexpr uint16_t ctsCharId {0x2a2b};
+ static constexpr uint16_t ctsCurrentTimeCharId {0x2a2b};
+ static constexpr uint16_t ctsLocalTimeCharId {0x2a0f};
static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId};
- static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId};
+ static constexpr ble_uuid16_t ctsCtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCurrentTimeCharId};
+ static constexpr ble_uuid16_t ctsLtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsLocalTimeCharId};
- struct ble_gatt_chr_def characteristicDefinition[2];
+ struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_svc_def serviceDefinition[2];
typedef struct __attribute__((packed)) {
- uint16_t year;
+ uint8_t year_LSO; // BLE GATT is little endian
+ uint8_t year_MSO;
uint8_t month;
uint8_t dayofmonth;
uint8_t hour;
uint8_t minute;
uint8_t second;
- uint8_t millis;
- uint8_t reason;
- } CtsData;
+ uint8_t dayofweek;
+ uint8_t fractions256; // currently ignored
+ uint8_t reason; // currently ignored, not that any host would set it anyway
+ } CtsCurrentTimeData;
+
+ typedef struct __attribute__((packed)) {
+ uint8_t timezone;
+ uint8_t dst;
+ } CtsLocalTimeData;
DateTime& m_dateTimeController;
};
diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp
index 4dc16329..8aab49ec 100644
--- a/src/components/datetime/DateTimeController.cpp
+++ b/src/components/datetime/DateTimeController.cpp
@@ -36,6 +36,7 @@ void DateTime::SetTime(uint16_t year,
/* .tm_mon = */ month - 1,
/* .tm_year = */ year - 1900,
};
+
tm.tm_isdst = -1; // Use DST value from local time zone
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
@@ -50,6 +51,11 @@ void DateTime::SetTime(uint16_t year,
systemTask->PushMessage(System::Messages::OnNewTime);
}
+void DateTime::SetTimeZone(uint8_t timezone, uint8_t dst) {
+ tzOffset = timezone;
+ dstOffset = dst;
+}
+
void DateTime::UpdateTime(uint32_t systickCounter) {
// Handle systick counter overflow
uint32_t systickDelta = 0;
diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h
index 81319d15..681bafbf 100644
--- a/src/components/datetime/DateTimeController.h
+++ b/src/components/datetime/DateTimeController.h
@@ -38,6 +38,18 @@ namespace Pinetime {
uint8_t minute,
uint8_t second,
uint32_t systickCounter);
+
+ /*
+ * setter corresponding to the BLE Set Local Time characteristic.
+ *
+ * used to update difference between utc and local time (see UtcOffset())
+ *
+ * parameters are in quarters of an our. Following the BLE CTS specification,
+ * timezone is expected to be constant over DST which will be reported in
+ * dst field.
+ */
+ void SetTimeZone(uint8_t timezone, uint8_t dst);
+
void UpdateTime(uint32_t systickCounter);
uint16_t Year() const {
return year;
@@ -61,6 +73,42 @@ namespace Pinetime {
return second;
}
+ /*
+ * returns the offset between local time and UTC in quarters of an hour
+ *
+ * Availability of this field depends on wether the companion app
+ * supports the BLE CTS Local Time Characteristic. Expect it to be 0
+ * if not.
+ */
+ uint8_t UtcOffset() const {
+ return tzOffset + dstOffset;
+ }
+
+ /*
+ * returns the offset between the (dst independent) local time zone and UTC
+ * in quarters of an hour
+ *
+ * Availability of this field depends on wether the companion app
+ * supports the BLE CTS Local Time Characteristic. Expect it to be 0
+ * if not.
+ */
+ uint8_t TzOffset() const {
+ return tzOffset;
+ }
+
+ /*
+ * returns the offset between the local time zone and local time
+ * in quarters of an hour
+ * if != 0, DST is in effect, if == 0 not.
+ *
+ * Availability of this field depends on wether the companion app
+ * supports the BLE CTS Local Time Characteristic. Expect it to be 0
+ * if not.
+ */
+ uint8_t DstOffset() const {
+ return dstOffset;
+ }
+
const char* MonthShortToString() const;
const char* DayOfWeekShortToString() const;
static const char* MonthShortToStringLow(Months month);
@@ -69,6 +117,9 @@ namespace Pinetime {
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
return currentDateTime;
}
+ std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const {
+ return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
+ }
std::chrono::seconds Uptime() const {
return uptime;
}
@@ -85,6 +136,8 @@ namespace Pinetime {
uint8_t hour = 0;
uint8_t minute = 0;
uint8_t second = 0;
+ uint8_t tzOffset = 0;
+ uint8_t dstOffset = 0;
uint32_t previousSystickCounter = 0;
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;