Skip to content

periph/rtc: normalize struct tm before usage#11413

Merged
maribu merged 3 commits intoRIOT-OS:masterfrom
benpicco:rtc_sanitize
Sep 12, 2019
Merged

periph/rtc: normalize struct tm before usage#11413
maribu merged 3 commits intoRIOT-OS:masterfrom
benpicco:rtc_sanitize

Conversation

@benpicco
Copy link
Copy Markdown
Contributor

@benpicco benpicco commented Apr 17, 2019

Contribution description

A naive implementation may set a RTC alarm in 30s by calling

struct tm now;
rtc_get_time(&now);
now.tm_sec += 30;
rtc_set_alarm(&now, _cb, NULL);

This works for RTC implementations that use a RTT internally and call mktime() to convert the struct tm to a unix timestamp, as mktime() will normalize the struct in the process.

On a RTC implementation where there is a separate register for minutes / seconds the alarm will never trigger if the current seconds are > 30.

Always call mktime() even when the RTC uses separate registers for time / date components to ensure it is normalized.

This also modifies tests/periph_rtc to exercise this case.

Testing procedure

Run tests/periph_rtc on a board with RTC.
4 Alarm!s should be triggered.

@benpicco benpicco force-pushed the rtc_sanitize branch 2 times, most recently from 01147d2 to 2d69d84 Compare April 17, 2019 17:59
@miri64 miri64 added Area: drivers Area: Device drivers Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) labels Apr 18, 2019
Copy link
Copy Markdown
Contributor

@fjmolinas fjmolinas left a comment

Choose a reason for hiding this comment

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

Nice catch, the current tests don't take this into account since only 4 alarms are triggered there never is an overflow. I tested your changes with and without normalizing on nucleo-l073rz, without this PR it just triggers one alarm and with this PR it works as expected. I also tested that there was no regression for samr21-xpro.

Everything looks good, I would just add a comment on rtc_set_alarm and rtc_set_time that states that the input time structure gets normalized.

I don't have any board using the other CPU's @maribu has a msba2 according to the wiki and @kaspar030 has a chronos, maybe they can test for those cpu's?

@maribu
Copy link
Copy Markdown
Member

maribu commented Jul 24, 2019

I tested with the MSB-A2. The periph_rtc is completely broken (unrelated to this PR).

I checked the manpage of mktime() and it should indeed normalize the time. Thus, it should theoretically fix the bug.

I'll have a look at the broken periph_rtc of the lpc2387 CPU.

+1 for merging this without having it tested on the MSB-A2 (but on the other three implementations). This fixes a real issue for the other CPU-families and should not be stalled IMO due to an unrelated bug. Also, this PR is not really scary and very unlikely to break anything.

@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 Aug 5, 2019
@benpicco benpicco force-pushed the rtc_sanitize branch 2 times, most recently from da98ddd to 15748e7 Compare August 13, 2019 23:03
@benpicco
Copy link
Copy Markdown
Contributor Author

benpicco commented Aug 13, 2019

Well it turns out not every platform has mktime() and for some other platforms, including mktime() tips them over the ROM size limit.

I've now introduced a rtc_tm_normalize() that should behave as a minimal mktime().
I will add testcases too if this approach is sensible.

Calculating tm_yday and tm_wday is optional, the RTC does not need it.

For examples/default and BOARD=chronos this gives:

before:

   text	   data	    bss	    dec	    hex	filename
  13116	     90	   1032	  14238	   379e	bin/chronos/default.elf

after:

   text	   data	    bss	    dec	    hex	filename
  13486	     90	   1032	  14608	   3910	bin/chronos/default.elf

after with RTC_NORMALIZE_COMPAT = 1

   text	   data	    bss	    dec	    hex	filename
  13786	     90	   1032	  14908	   3a3c	bin/chronos/default.elf

@benpicco benpicco force-pushed the rtc_sanitize branch 2 times, most recently from 9379591 to 97667fc Compare August 13, 2019 23:38
@fjmolinas
Copy link
Copy Markdown
Contributor

Code looks good. msp430-gcc seems to be doing a worse job at optimizing the rtc_tm_normalize(), 502 bytes vs 242/280 bytes for arm-gcc (depending on platform), both compiled in docker.

@fjmolinas
Copy link
Copy Markdown
Contributor

For chronos rtc code size has almost doubled with this addition. But I still think we should include this. Timing is important enough to spend the memory on getting it correctly, I might want to check if we can optimize it a bit though.

@benpicco
Copy link
Copy Markdown
Contributor Author

benpicco commented Aug 14, 2019

Using div() to get both quotient and remainder in one go sheds some more bytes. Down to 458 370 bytes extra on BOARD=chronos now.

@benpicco benpicco force-pushed the rtc_sanitize branch 2 times, most recently from 83ae633 to a605c44 Compare August 14, 2019 12:25
@benpicco benpicco requested a review from fjmolinas September 11, 2019 13:43
@fjmolinas fjmolinas added Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines Reviewed: 5-documentation The documentation details of the PR were reviewed according to the maintainer guidelines labels Sep 12, 2019
@fjmolinas
Copy link
Copy Markdown
Contributor

Tests are still passing for me. Changes are looking good to, thanks for the unit-test addition.

@kaspar030 can you find time to test on chronos? If not I think we should just move forward with the PR.

Copy link
Copy Markdown
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

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

OK, codewise I'd ACK. With the PR not changing hardware interactions, I think there is no reason to test it on every board, but testing on one should be more that enough.

Some of the code is pretty magic, which needs more explanation. I marked those sections inline and tried to already suggest comments that could explain the magic. Afterwards, I will ACK.

@maribu maribu added the Reviewed: 3-testing The PR was tested according to the maintainer guidelines label Sep 12, 2019
@maribu
Copy link
Copy Markdown
Member

maribu commented Sep 12, 2019

Btw: Please squash right away (including the added comments).

@maribu maribu added the CI: run tests If set, CI server will run tests on hardware for the labeled PR label Sep 12, 2019
@benpicco
Copy link
Copy Markdown
Contributor Author

benpicco commented Sep 12, 2019

@maribu thank you for the comments! I added them all except the inline one inside the array members , that one just adds clutter imho and the logic is already explained above.

benpicco and others added 3 commits September 12, 2019 11:32
A naive implementation may set a RTC alarm in 30s by calling

	struct tm now;
	rtc_get_time(&now);
	now.tm_sec += 30;
	rtc_set_alarm(&now, _cb, NULL);

This works for RTC implementations that use a RTT internally and call
mktime() to convert the struct tm to a unix timestamp, as mktime() will
normalize the struct in the process.

Call rtc_tm_normalize() when the RTC uses separate registers for time / date
components to ensure it is normalized.

This also modifies tests/periph_rtc to exercise this case.
Copy link
Copy Markdown
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

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

ACK!

@maribu maribu merged commit c262770 into RIOT-OS:master Sep 12, 2019
@benpicco benpicco deleted the rtc_sanitize branch September 12, 2019 11:05
@kb2ma kb2ma added this to the Release 2019.10 milestone Sep 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: drivers Area: Device drivers CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR CI: run tests If set, CI server will run tests on hardware for the labeled PR Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines Reviewed: 5-documentation The documentation details of the PR were reviewed according to the maintainer guidelines Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants