-
Notifications
You must be signed in to change notification settings - Fork 2.1k
sys/walltime: add module for system time #21343
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
base: master
Are you sure you want to change the base?
Conversation
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.
I like this addition a lot, some small comments and observations from testing the PR below.
Edit: For reference: I tested this with an nRF52840DK with USEMODULE+=walltime BOARD=nrf52840dk make -C tests/sys/shell flash term
.
* @brief Common functions to access the wall-clock / real time clock | ||
* @{ | ||
* @file | ||
* |
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.
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.
Also since there is no documentation for struct tm
(I think time.h
is part of the standard library?), it might be good to include a link to a reference for it.
This is the link used by drivers/periph/rtc.h
: https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
RIOT/drivers/include/periph/rtc.h
Lines 17 to 20 in 85dc9be
* @note | |
* The values used for setting and getting the time/alarm should | |
* conform to the `struct tm` specification. | |
* Compare: http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html |
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.
Nice, I like this! Some first thoughts on it below.
struct tm now; | ||
walltime_get(&now, ms); | ||
return mktime(&now); |
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.
Since you are providing a ZTIMER_FALLBACK
above, what would happen here if periph_rtc
and rtt_rtc
are not available?
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.
The system time will always start at RIOT_EPOCH
at boot, but still can by synced later on e.g. via NTP - it's just not persistent across reboots.
#endif | ||
|
||
static uint32_t _boottime; | ||
#ifdef BACKUP_RAM |
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.
Is that macro documented somewhere?
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.
Does this count?
$ rg BACKUP_RAM -B 5 features.yaml
417-- title: RAM Related Features
418- help: These features indicate presence of special RAM regions or features
419- features:
420- - name: backup_ram
421- help: A special portion of RAM is retained during deep sleep.
422: Variables can be placed there by annotating them with the `BACKUP_RAM`
See https://doc.riot-os.org/feature-list.html#autotoc_md2404 for the output
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.
Hum, that's indeed something, but probably nothing doxygen would find when using @ref BACKUP_RAM
uint32_t msec = 0; | ||
#ifdef ZTIMER_FALLBACK | ||
rtc_localtime(walltime_get_riot(ms), time); | ||
#elif defined(MODULE_PERIPH_RTC_MS) |
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.
Is it on purpose that you check for MODULE_PERIPH_RTC
above for ZTIMER_FALLBACK
?
static uint32_t _boottime_bkup; | ||
#endif | ||
#ifdef ZTIMER_FALLBACK | ||
uint32_t ztimer_offset; |
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.
even though i rarely run my devboards for 50 days or longer there should be a "mitigation for the 49day overflow"
eg a overflow counter
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.
ah here: uint32_t now = ztimer_now(ZTIMER_MSEC);
you mean.
|
||
void walltime_set(struct tm *time) | ||
{ | ||
int32_t diff = rtc_mktime(time) - walltime_get_riot(NULL); |
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.
I think the int32_t
could lead to unexpected results. For example the extreme case 0 - 4294967295
becomes 1
.
I would expect -4294967295
You could figure out the sign and compute the number as uint32_t
higher - lower.
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.
diff --git a/sys/walltime/walltime.c b/sys/walltime/walltime.c
index 903e856a16..5171cb0770 100644
--- a/sys/walltime/walltime.c
+++ b/sys/walltime/walltime.c
@@ -17,6 +17,8 @@
*
* @}
*/
+#include <stdio.h>
+
#include "auto_init.h"
#include "auto_init_utils.h"
#include "auto_init_priorities.h"
@@ -96,7 +98,10 @@ time_t walltime_get_unix(uint16_t *ms)
void walltime_set(struct tm *time)
{
- int32_t diff = rtc_mktime(time) - walltime_get_riot(NULL);
+ uint32_t t;
+ int32_t w;
+ int32_t diff = (t = rtc_mktime(time)) - (w = walltime_get_riot(NULL));
+ printf("t %"PRIu32" - w %"PRId32" = diff %"PRId32"\n", t, w, diff);
_boottime += diff;
#ifdef BACKUP_RAM
_boottime_bkup += diff;
> 2025-05-06 15:29:20,168 # main(): This is RIOT! (Version: 2025.04-devel-522-g90fc5e-walltime)
> walltime set 4000-01-01 00:00:00
2025-05-06 15:29:23,464 # walltime set 4000-01-01 00:00:00
2025-05-06 15:29:23,480 # t 2353209856 - w 3 = diff -1941757443
2025-05-06 15:29:23,481 # time changed by -1941757443 sec, 0 ms
So when going very very very far in the future, the diff becomes negative.
I know that no one actually cares about the year 4000, but consider some user input or malformed network packet ... whatever.
* | ||
* @} | ||
*/ | ||
#include "auto_init.h" |
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.
maybe guard with IS_USED(MODULE_AUTO_INIT)
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.
But why?
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.
Because when it would be used with unittest it would fail to compile, or when someone does not want auto_init
.
I would say if the auto init stuff is not guarded, USEMODULE += auto_init
would belong in Makefile.dep
.
But auto_init
is not necessarily required.
Too much worries or do you agree that any auto init stuff should be guarded?
return now - _boottime; | ||
} | ||
|
||
static void auto_init_uptime(void) |
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.
maybe guard with IS_USED(MODULE_AUTO_INIT_WALLTIME/UPTIME)
How would I implement an on-time change callback? |
We can add that to the I wanted to get the core API in first, but might as well already add this here.
Yea applications must not use the
There only is a single wall time/system time. I'm happy to hook up different backends like |
* | ||
* @param[in] time The current data / time to set | ||
*/ | ||
void walltime_set(struct tm *time); |
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.
If rtc_set_time
returns an int
, then walltime_set
also should be capable to return an error.
There could be an external I2C RTC which could report a communication error.
* @param[out] ms current milliseconds output, may be NULL | ||
* always returns 0 if the backend supports no millisecond resolution | ||
*/ | ||
void walltime_get(struct tm *time, uint16_t *ms); |
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.
also here I would vote for an int
return type
return 8; | ||
} | ||
|
||
|
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.
double empty line
The walltime is calling Consider the case of an external RTC. There is the option to wrap the driver RTC API in our periph RTC API.
If the walltime would not use the RTC API but use a driver struct with function callbacks, then the walltime could be instanciated with either the periph RTC or the external RTC driver. Then periph RTC features could still be used. |
Contribution description
Currently applications use the
periph_rtc
API directly if they want to track wall clock time.This leads to problems when the time is not provided by
periph_rtc
but some external RTC or when we want to perform actions e.g. on setting the time - then this has to be hooked up with everyperiph_rtc
implementation.Instead, provide a wrapper API that applications can use to obtain the current system time without accessing the RTC API directly.
This allows to write applications that are agnostic to the availability of
periph_rtc
and still can provide some proper timestamps.Testing procedure
Enable the
walltime
module.This will provide a
walltime
command to get / set the time and display the time since last boot.Issues/PRs references
Alternative to #17416, #21366