Skip to content

Commit d7e4f79

Browse files
committed
Continuous time update - Alternative implementation to #2041
This is an alternative implementation to #2041 we talked about in this comment (#2041 (comment)). This implementation does not change the state of the DateTime controller (previousSystickCounter and currentDateTime fields) in GetCurrentDateTime(). This allows to keep the method GetCurrentDateTime() const. I also applied a small refactoring of the methods UpdateTime() to avoid trying to lock the same mutex multiple times (FreeRTOS mutexes are not reentrant). Co-authored-by: 30447455+mark9064@users.noreply.github.com
1 parent 06c6935 commit d7e4f79

File tree

3 files changed

+59
-25
lines changed

3 files changed

+59
-25
lines changed

src/components/datetime/DateTimeController.cpp

+49-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "components/datetime/DateTimeController.h"
22
#include <libraries/log/nrf_log.h>
33
#include <systemtask/SystemTask.h>
4+
#include <nrf_rtc.h>
45

56
using namespace Pinetime::Controllers;
67

@@ -12,11 +13,16 @@ namespace {
1213
}
1314

1415
DateTime::DateTime(Controllers::Settings& settingsController) : settingsController {settingsController} {
16+
mutex = xSemaphoreCreateMutex();
17+
ASSERT(mutex != nullptr);
18+
xSemaphoreGive(mutex);
1519
}
1620

1721
void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
22+
xSemaphoreTake(mutex, portMAX_DELAY);
1823
this->currentDateTime = t;
1924
UpdateTime(previousSystickCounter); // Update internal state without updating the time
25+
xSemaphoreGive(mutex);
2026
}
2127

2228
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
@@ -35,7 +41,9 @@ void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
3541
NRF_LOG_INFO("%d %d %d ", day, month, year);
3642
NRF_LOG_INFO("%d %d %d ", hour, minute, second);
3743

44+
xSemaphoreTake(mutex, portMAX_DELAY);
3845
UpdateTime(previousSystickCounter);
46+
xSemaphoreGive(mutex);
3947

4048
systemTask->PushMessage(System::Messages::OnNewTime);
4149
}
@@ -45,29 +53,23 @@ void DateTime::SetTimeZone(int8_t timezone, int8_t dst) {
4553
dstOffset = dst;
4654
}
4755

48-
void DateTime::UpdateTime(uint32_t systickCounter) {
56+
uint32_t DateTime::GetTickFromPreviousSystickCounter(uint32_t systickCounter) const {
4957
// Handle systick counter overflow
5058
uint32_t systickDelta = 0;
5159
if (systickCounter < previousSystickCounter) {
52-
systickDelta = 0xffffff - previousSystickCounter;
60+
systickDelta = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - previousSystickCounter;
5361
systickDelta += systickCounter + 1;
5462
} else {
5563
systickDelta = systickCounter - previousSystickCounter;
5664
}
65+
return systickDelta;
66+
}
5767

58-
/*
59-
* 1000 ms = 1024 ticks
60-
*/
61-
auto correctedDelta = systickDelta / 1024;
62-
auto rest = systickDelta % 1024;
63-
if (systickCounter >= rest) {
64-
previousSystickCounter = systickCounter - rest;
65-
} else {
66-
previousSystickCounter = 0xffffff - (rest - systickCounter);
67-
}
68-
69-
currentDateTime += std::chrono::seconds(correctedDelta);
70-
uptime += std::chrono::seconds(correctedDelta);
68+
void DateTime::UpdateTime() {
69+
xSemaphoreTake(mutex, portMAX_DELAY);
70+
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
71+
UpdateTime(systick_counter);
72+
xSemaphoreGive(mutex);
7173

7274
std::time_t currentTime = std::chrono::system_clock::to_time_t(currentDateTime);
7375
localTime = *std::localtime(&currentTime);
@@ -103,6 +105,23 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
103105
}
104106
}
105107

108+
void DateTime::UpdateTime(uint32_t systickCounter) {
109+
auto systickDelta = GetTickFromPreviousSystickCounter(systickCounter);
110+
auto correctedDelta = systickDelta / configTICK_RATE_HZ;
111+
112+
/*
113+
* 1000 ms = 1024 ticks
114+
*/
115+
auto rest = systickDelta % configTICK_RATE_HZ;
116+
if (systickCounter >= rest) {
117+
previousSystickCounter = systickCounter - rest;
118+
} else {
119+
previousSystickCounter = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - (rest - systickCounter);
120+
}
121+
currentDateTime += std::chrono::seconds(correctedDelta);
122+
uptime += std::chrono::seconds(correctedDelta);
123+
}
124+
106125
const char* DateTime::MonthShortToString() const {
107126
return MonthsString[static_cast<uint8_t>(Month())];
108127
}
@@ -146,3 +165,18 @@ std::string DateTime::FormattedTime() {
146165
}
147166
return std::string(buff);
148167
}
168+
169+
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> DateTime::CurrentDateTime() const {
170+
xSemaphoreTake(mutex, portMAX_DELAY);
171+
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
172+
auto correctedDelta = GetTickFromPreviousSystickCounter(systick_counter) / configTICK_RATE_HZ;
173+
auto result = currentDateTime + std::chrono::seconds(correctedDelta);
174+
;
175+
xSemaphoreGive(mutex);
176+
177+
return result;
178+
}
179+
180+
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> DateTime::UTCDateTime() const {
181+
return CurrentDateTime() - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
182+
}

src/components/datetime/DateTimeController.h

+9-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <chrono>
55
#include <ctime>
66
#include <string>
7+
#include <FreeRTOS.h>
8+
#include <semphr.h>
79
#include "components/settings/Settings.h"
810

911
namespace Pinetime {
@@ -45,7 +47,7 @@ namespace Pinetime {
4547
*/
4648
void SetTimeZone(int8_t timezone, int8_t dst);
4749

48-
void UpdateTime(uint32_t systickCounter);
50+
void UpdateTime();
4951

5052
uint16_t Year() const {
5153
return 1900 + localTime.tm_year;
@@ -124,13 +126,9 @@ namespace Pinetime {
124126
static const char* MonthShortToStringLow(Months month);
125127
static const char* DayOfWeekShortToStringLow(Days day);
126128

127-
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
128-
return currentDateTime;
129-
}
129+
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const;
130130

131-
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const {
132-
return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
133-
}
131+
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const;
134132

135133
std::chrono::seconds Uptime() const {
136134
return uptime;
@@ -141,6 +139,9 @@ namespace Pinetime {
141139
std::string FormattedTime();
142140

143141
private:
142+
uint32_t GetTickFromPreviousSystickCounter(uint32_t systickCounter) const;
143+
void UpdateTime(uint32_t systickCounter);
144+
144145
std::tm localTime;
145146
int8_t tzOffset = 0;
146147
int8_t dstOffset = 0;
@@ -154,6 +155,7 @@ namespace Pinetime {
154155
bool isHalfHourAlreadyNotified = true;
155156
System::SystemTask* systemTask = nullptr;
156157
Controllers::Settings& settingsController;
158+
SemaphoreHandle_t mutex = nullptr;
157159
};
158160
}
159161
}

src/systemtask/SystemTask.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "systemtask/SystemTask.h"
2-
#include <hal/nrf_rtc.h>
32
#include <libraries/gpiote/app_gpiote.h>
43
#include <libraries/log/nrf_log.h>
54
#include "BootloaderVersion.h"
@@ -410,8 +409,7 @@ void SystemTask::Work() {
410409
}
411410

412411
monitor.Process();
413-
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
414-
dateTimeController.UpdateTime(systick_counter);
412+
dateTimeController.UpdateTime();
415413
NoInit_BackUpTime = dateTimeController.CurrentDateTime();
416414
if (nrf_gpio_pin_read(PinMap::Button) == 0) {
417415
watchdog.Reload();

0 commit comments

Comments
 (0)