drivers: rtc: Create utility function for time validation

RTC drivers should validate the `struct rtc_time`'s contents against the
provided `mask`. Promote this common code to a new rtc_utils file and
modify existing drivers to use this functionality. Extend the test
coverage to include verifying this behaviour.

This is groundwork ahead of adding support for the RP2040's (as used in
the Raspberry Pi Pico) RTC and alarm.

Signed-off-by: Andrew Featherstone <andrew.featherstone@gmail.com>
This commit is contained in:
Andrew Featherstone 2024-02-25 13:12:35 +00:00 committed by Fabio Baltieri
commit 4c880f4b0a
11 changed files with 200 additions and 74 deletions

View file

@ -5,6 +5,8 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/rtc.h)
zephyr_library()
zephyr_library_sources(rtc_utils.c)
zephyr_library_sources_ifdef(CONFIG_RTC_AM1805 rtc_am1805.c)
zephyr_library_sources_ifdef(CONFIG_RTC_DS1307 rtc_ds1307.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c)

View file

@ -10,6 +10,8 @@
#include <zephyr/device.h>
#include <zephyr/drivers/rtc.h>
#include "rtc_utils.h"
struct rtc_emul_data;
struct rtc_emul_work_delayable {
@ -67,43 +69,6 @@ static bool rtc_emul_is_leap_year(struct rtc_time *datetime)
return false;
}
#ifdef CONFIG_RTC_ALARM
static bool rtc_emul_validate_alarm_time(const struct rtc_time *timeptr, uint32_t mask)
{
if ((mask & RTC_ALARM_TIME_MASK_SECOND) &&
(timeptr->tm_sec < 0 || timeptr->tm_sec > 59)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MINUTE) &&
(timeptr->tm_min < 0 || timeptr->tm_min > 59)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_HOUR) &&
(timeptr->tm_hour < 0 || timeptr->tm_hour > 23)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MONTH) &&
(timeptr->tm_mon < 0 || timeptr->tm_mon > 11)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) &&
(timeptr->tm_mday < 1 || timeptr->tm_mday > 31)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_YEAR) &&
(timeptr->tm_year < 0 || timeptr->tm_year > 199)) {
return false;
}
return true;
}
#endif /* CONFIG_RTC_ALARM */
static int rtc_emul_get_days_in_month(struct rtc_time *datetime)
{
const uint8_t *dim = (rtc_emul_is_leap_year(datetime) == true) ?
@ -346,7 +311,7 @@ static int rtc_emul_alarm_set_time(const struct device *dev, uint16_t id, uint16
}
if (mask > 0) {
if (rtc_emul_validate_alarm_time(timeptr, mask) == false) {
if (rtc_utils_validate_rtc_time(timeptr, mask) == false) {
return -EINVAL;
}
}

View file

@ -26,6 +26,11 @@
#define RTC_SAM_CALIBRATE_PPB_QUANTA (1500)
#define RTC_SAM_CALIBRATE_PPB_LOW_SCALE (30500)
#define RTC_SAM_TIME_MASK \
(RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | \
RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_YEAR | \
RTC_ALARM_TIME_MASK_WEEKDAY)
typedef void (*rtc_sam_irq_init_fn_ptr)(void);
struct rtc_sam_config {
@ -58,41 +63,6 @@ static void rtc_sam_enable_wp(void)
REG_RTC_WPMR = RTC_SAM_WPMR_ENABLE;
}
static bool rtc_sam_validate_tm(const struct rtc_time *timeptr, uint32_t mask)
{
if ((mask & RTC_ALARM_TIME_MASK_SECOND) &&
(timeptr->tm_sec < 0 || timeptr->tm_sec > 59)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MINUTE) &&
(timeptr->tm_min < 0 || timeptr->tm_min > 59)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_HOUR) &&
(timeptr->tm_hour < 0 || timeptr->tm_hour > 23)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MONTH) &&
(timeptr->tm_mon < 0 || timeptr->tm_mon > 11)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) &&
(timeptr->tm_mday < 1 || timeptr->tm_mday > 31)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_YEAR) &&
(timeptr->tm_year < 0 || timeptr->tm_year > 199)) {
return false;
}
return true;
}
static uint32_t rtc_sam_timr_from_tm(const struct rtc_time *timeptr)
{
uint32_t timr;
@ -126,7 +96,7 @@ static int rtc_sam_set_time(const struct device *dev, const struct rtc_time *tim
const struct rtc_sam_config *config = dev->config;
Rtc *regs = config->regs;
if (rtc_sam_validate_tm(timeptr, UINT32_MAX) == false) {
if (rtc_utils_validate_rtc_time(timeptr, RTC_SAM_TIME_MASK) == false) {
return -EINVAL;
}

58
drivers/rtc/rtc_utils.c Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2023 Bjarki Arge Andreasen
* Copyright (c) 2024 Andrew Featherstone
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdint.h>
#include <zephyr/drivers/rtc.h>
#include "rtc_utils.h"
bool rtc_utils_validate_rtc_time(const struct rtc_time *timeptr, uint16_t mask)
{
if ((mask & RTC_ALARM_TIME_MASK_SECOND) && (timeptr->tm_sec < 0 || timeptr->tm_sec > 59)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MINUTE) && (timeptr->tm_min < 0 || timeptr->tm_min > 59)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_HOUR) && (timeptr->tm_hour < 0 || timeptr->tm_hour > 23)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MONTH) && (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) &&
(timeptr->tm_mday < 1 || timeptr->tm_mday > 31)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_YEAR) && (timeptr->tm_year < 0 || timeptr->tm_year > 199)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_WEEKDAY) &&
(timeptr->tm_wday < 0 || timeptr->tm_wday > 6)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_YEARDAY) &&
(timeptr->tm_yday < 0 || timeptr->tm_yday > 365)) {
return false;
}
if ((mask & RTC_ALARM_TIME_MASK_NSEC) &&
(timeptr->tm_nsec < 0 || timeptr->tm_nsec > 999999999)) {
return false;
}
return true;
}

28
drivers/rtc/rtc_utils.h Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 Bjarki Arge Andreasen
* Copyright (c) 2024 Andrew Featherstone
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_RTC_RTC_UTILS_H_
#define ZEPHYR_DRIVERS_RTC_RTC_UTILS_H_
#include <stdbool.h>
#include <stdint.h>
#include <zephyr/drivers/rtc.h>
/**
* @brief Validate a datetime with a mask
*
* Ensure that any fields selected by mask contain a valid value.
*
* @param timeptr The time to set
* @param mask Mask of fields to validate
*
* @return true if the required fields are valid.
*/
bool rtc_utils_validate_rtc_time(const struct rtc_time *timeptr, uint16_t mask);
#endif /* ZEPHYR_DRIVERS_RTC_RTC_UTILS_H_ */