Skip to content
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

Add RTC time change notifications #17416

Conversation

DanielLockau-MLPA
Copy link
Contributor

Contribution description

Relating to real (wall clock) time is required in many applications. Knowing about shifts in real time due to setting the clock can be crucial in some application contexts and building up a monitoring within the application can be considered too expensive. Applications also can may have several sources for changing the system's wall time, e.g. the console, a GNSS module or NTP.

As all sources for time changes to the wall time will use the periph/rtc or drivers/rtt_rtc APIs, we propose to add time change notifications to the time setter API functions within those modules. Notifications are distributed to subscribers through a system bus for RTC events.

To enable queuing of multiple additive time change events, we propose to add the amount of time difference created between old wall time and new wall time events as int32_t content in milliseconds to each message. This enables communication of time differences in milliseconds within about +-24.8 days and an out of range special value (INT32_MIN). One might instead consider a singleton to signal larger time differences as multiple queuing is quite improbable. However, wall time changes of more than 24 days are also quite improbable in a running system and by enabling queuing of multiple additive changes we can achieve consistency within that period even if the application shows some misbehavior.

Testing procedure

  • the unit test for periph/rtc was extended to test the time difference computation
  • the test for periph/rtc was extended to test the time change notifications

Issues/PRs references

None.

@github-actions github-actions bot added Area: cpu Area: CPU/MCU ports Area: drivers Area: Device drivers Area: sys Area: System Area: tests Area: tests and testing framework Platform: ARM Platform: This PR/issue effects ARM-based platforms Platform: AVR Platform: This PR/issue effects AVR-based platforms Platform: native Platform: This PR/issue effects the native platform Platform: RISC-V Platform: This PR/issue effects RISC-V-based platforms labels Dec 16, 2021
@kaspar030
Copy link
Contributor

Would it make sense to rename the existing rtc_set_time(), and do the sysbus stuff once, calling the renamed ones?

@DanielLockau-MLPA
Copy link
Contributor Author

Would it make sense to rename the existing rtc_set_time(), and do the sysbus stuff once, calling the renamed ones?

I also thought about having a single place for the implementation but some of the rtc implementations support sub-second precision and others don't. I would also like to support rtt_rtc which has an additional setter method apart from the rtc interface which is why I set this idea aside.

@kaspar030
Copy link
Contributor

I'm not entirely sure if these notification should be part of periph_rtc.

@maribu
Copy link
Member

maribu commented Dec 16, 2021

I'm not entirely sure if these notification should be part of periph_rtc.

How about providing a callback (no need to waste RAM and ROM on function pointers here IMO, just extern void rtc_changed_callback(time_old, time_new)) and hook the bus interface in there (by implementing that callback)? If someone wants the callback without the bus, they could implement their own callback function with this.

@github-actions github-actions bot removed Platform: AVR Platform: This PR/issue effects AVR-based platforms Platform: native Platform: This PR/issue effects the native platform labels Jan 3, 2022
@DanielLockau-MLPA
Copy link
Contributor Author

I finally got back to this and addressed existing comments. Not sure whether this proposal will fit coding conventions though.

  • @kaspar030 I reduced code impact by wrapping rtc_set_time into another function call instead of creating copy-paste content
  • @maribu I separated the time change notification on the system bus from periph/rtc by adding a callback as proposed by you
  • @kaspar030 the first commit addresses a probable issue in the implementation of cpu/lpc23xx, however I don't have the means to test it. Comparing to the data sheet I seems like a typo was made during the rtc implementation. If you confirm, I can move this to another branch as it is unrelated.

Generally a good number of rtc implementations seem to reset the sub-second timer whenever the time is reset. A few don't seem to do that. I would generally argue that the provided date should be precise and sub-second timing should be reset to the provided time stamp's precision. I actually encountered a test failure on native following an unexpected rollover due to this issue (notice the seconds value following No alarm at which was expected to be identical to the alarm value previously set):

 % make test                                                       
r
/home/daniel_lockau/src/IoT_RIOT_Products/ext/RIOT/tests/periph_rtc/bin/native/tests_periph_rtc.elf /dev/ttyACM0 
RIOT native interrupts/signals initialized.
LED_RED_OFF
LED_GREEN_ON
RIOT native board initialized.
RIOT native hardware initialization complete.

Help: Press s to start test, r to print it is ready
READY
s
START
main(): This is RIOT! (Version: 2022.01-devel-1319-g5bf5ae1-feat/20211108__sys-bus__add_rtc_bus)

RIOT RTC low-level driver test
This test will display 'Alarm!' every 2 seconds for 4 times
Native RTC initialized.
  Setting clock to   2020-02-28 23:59:57
Clock value is now   2020-02-28 23:59:57
Resetting clock to   2020-02-29 00:00:39
    Time change of   42000 milliseconds
  Setting alarm to   2020-02-29 00:00:41
   Alarm is set to   2020-02-29 00:00:41
  Alarm cleared at   2020-02-29 00:00:39
       No alarm at   2020-02-29 00:00:42
  Setting alarm to   2020-02-29 00:00:44


Traceback (most recent call last):
  File "/home/daniel_lockau/src/IoT_RIOT_Products/ext/RIOT/tests/periph_rtc/tests/01-run.py", line 52, in <module>
    sys.exit(run(testfunc))
  File "/home/daniel_lockau/src/IoT_RIOT_Products/ext/RIOT/dist/pythonlibs/testrunner/__init__.py", line 30, in run
    testfunc(child)
  File "/home/daniel_lockau/src/IoT_RIOT_Products/ext/RIOT/tests/periph_rtc/tests/01-run.py", line 44, in testfunc
    assert alarm_value == no_alarm_value
AssertionError
make: *** [/home/daniel_lockau/src/IoT_RIOT_Products/ext/RIOT/makefiles/tests/tests.inc.mk:22: test] Error 1

Copy link
Contributor

@benpicco benpicco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, but needs a rebase. Code was moved from periph_common/rtc.c to sys/rtc_utils

@benpicco benpicco force-pushed the feat/20211108__sys-bus__add_rtc_bus branch from b64abfb to b40cf3f Compare February 8, 2022 22:20
@benpicco benpicco added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Feb 8, 2022
@benpicco benpicco force-pushed the feat/20211108__sys-bus__add_rtc_bus branch 2 times, most recently from cc1043b to 1a38ed4 Compare February 9, 2022 10:13
@github-actions github-actions bot added the Area: Kconfig Area: Kconfig integration label Feb 9, 2022
@MrKevinWeiss MrKevinWeiss added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Feb 9, 2022
@@ -258,3 +259,23 @@ bool rtc_tm_valid(const struct tm *t)
rtc_tm_normalize(&norm);
return rtc_tm_compare(t, &norm) == 0;
}

#ifdef MODULE_PERIPH_RTC_SETTER_CALLBACK
int rtc_set_time_with_callback(struct tm *time)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if it wouldn't be better to rename rtc_set_time() to e.g. rtc_set_time_dev() or whatever. That could also be extended to directly provide the previous values (including the ms parameter) for improved robustness. And rtc_set_time() would than be a common wrapper on top, which either just replicates the old behavior (if module periph_rtc_setter_callback is not used), or calls the callback.

I fear that this feature might be a footgun if one has to ensure that all calls of rtc_set_time() will be replaced with rtc_set_time_with_callback() to work correctly.

I am aware that this would involve touching all RTC implementations...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely agree with you on the footgun. I just wanted to reduce my impact on code with this second proposal. I am willing to rework this PR accordingly but it might take some weeks until I get back to it as I am currently under a relatively high load.

@stale
Copy link

stale bot commented Nov 2, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Nov 2, 2022
- substitute usage of CCR (clock control register) register
  by CTC (clock tick counter) in rtc_get_time_ms
- reset CTC register on rtc_set_time
- add pseudomodule `periph_rtc_setter_callback`
- implementation of callback required elsewhere
- add wrapper function for rtc_set_time to call with
  callback
- add RTC_SET_TIME define for switching between setter
  functions in applications
- add bus for rtc events
- declare time change notification event
@benpicco benpicco force-pushed the feat/20211108__sys-bus__add_rtc_bus branch from 1a38ed4 to ae804c1 Compare April 5, 2024 12:09
@stale stale bot removed the State: stale State: The issue / PR has no activity for >185 days label Apr 5, 2024
@github-actions github-actions bot removed the Area: Kconfig Area: Kconfig integration label Apr 5, 2024
@riot-ci
Copy link

riot-ci commented Apr 5, 2024

Murdock results

FAILED

ae804c1 sys/bus: implement time change notification

Success Failures Total Runtime
3621 0 9394 04m:24s

Artifacts

@fabian18
Copy link
Contributor

fabian18 commented Aug 4, 2024

I think this needs an update. The rtc_setter_callback is no longer compiled in to our app, because when the module is enabled, the build system complains about an unknown feature. There is now a features.yaml configuration file to generate Makefile.features. Every periph_ module is a feature. I think a normal pseudomodule rtc_setter_callback would be more appropriate. Because the callback is not provided by MCU or board, but by application.

@DanielLockau-MLPA
Copy link
Contributor Author

DanielLockau-MLPA commented Aug 5, 2024

I think this needs an update.

At the time of opening this PR, it seemed sensible to add this feature to RIOT but the number of use cases for this might not justify adding this feature on OS level. Adding an external wrapper layer to be used in specific applications should do the trick as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: cpu Area: CPU/MCU ports Area: drivers Area: Device drivers Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants