-
-
Notifications
You must be signed in to change notification settings - Fork 984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Continuous time update - Alternative implementation to #2041 #2054
Conversation
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
Build size and comparison to main:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is certainly an improvement over the current implementation (regarding current time reporting).
However, it does cause Seconds()
Minutes()
to desynchronise from the current reported time, as these methods use localTime
which is only updated whenever the system task / full update runs.
Therefore a pattern we have across the codebase
currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes();
uint8_t second = dateTimeController.Seconds();
is broken by this changeset. Due to DirtyValue
usage, the time will then not be updated for another second.
I see two fixes:
- Do a full state update each time (closer to what my PR does)
- Refactor the rest of the codebase to remove these
Seconds()
etc functions etc or to change these to calculate from the current time
In my opinion the API of Seconds()
etc is poorly designed. In most operating systems, you first fetch the current time and then you convert the time stamp you received to minutes, seconds, hours, whatever you need. InfiniTime should probably promote this conversion strategy. I believe modern C++ time handling should allow this fairly easily? (if it does not, we should probably create a new type that implements an interface similar to the one below)
So the above example becomes (pseudocode)
currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
uint8_t hour = currentDateTime.ToHours();
uint8_t minute = currentDateTime.ToMinutes();
uint8_t second = currentDateTime.ToSeconds();
and then the problem is resolved. This also resolves the problem of another task updating localTime
between for example a Minutes()
and Seconds()
call which removes a possible inconsistency.
xSemaphoreTake(mutex, portMAX_DELAY); | ||
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); | ||
UpdateTime(systick_counter); | ||
xSemaphoreGive(mutex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably extend the critical section to include updating localTime
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); | ||
auto correctedDelta = GetTickFromPreviousSystickCounter(systick_counter) / configTICK_RATE_HZ; | ||
auto result = currentDateTime + std::chrono::seconds(correctedDelta); | ||
; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting typo?
; |
if (systickCounter >= rest) { | ||
previousSystickCounter = systickCounter - rest; | ||
} else { | ||
previousSystickCounter = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - (rest - systickCounter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
previousSystickCounter = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - (rest - systickCounter); | |
previousSystickCounter = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - (rest - systickCounter - 1); |
previousSystickCounter should semantically be systickCounter - rest
Suppose rest = 1, sysTickCounter = 0
previousSystickCounter should be portNRF_RTC_MAXTICKS
but instead is portNRF_RTC_MAXTICKS - 1
@mark9064 Thank yo so much for this review! When reading your comment, it occurred to me that redesigning the whole So here's my suggestion : Add a Here is what this TODO file might look like: Refactoring neededContextThe PR #2041 - Continuous time update highlighted some limitations in the design of DateTimeController: the granularity of the time returned by @mark9064 provided more details in this comment. The PR #2041 - Continuous time update provided some changes to However, the review showed that We tried to identify alternative implementation that would have maintained the "const correctness" but we eventually figured that this would lead to a re-design of So we decided to merge this PR #2041 and agree to fix/improve What needs to be done?Improve/redesign
Once this redesign is implemented, all instances/references to Please check the following PR to get more context about this redesign: |
Closing in favor of #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).
To test it, I slowed down SystemTask so that it runs every 5s and DisplayApp every 1s. In both tasks, I logged the return of GetCurrentDateTime().
On the original implementation, the result was:
DisplayTAsk didn't get any new value until SystemTask updated the current time.
With this implementation:
As you can see, DisplayTask gets intermediate results between 2 updates from SystemTask.
@mark9064 What do you think of this?