blob: fcaf187dbf6a6d8951b04a346c5f9afd25f5148e [file] [log] [blame]
/*
* Copyright 2022 Bjarki Arge Andreasen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/device.h>
#include <zephyr/drivers/rtc.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/timeutil.h>
#include <zephyr/sys/util.h>
#include <time.h>
/* Fri Jan 01 2021 13:29:50 GMT+0000 */
#define RTC_TEST_ALARM_SET_TIME (1609507790)
#define RTC_TEST_ALARM_TEST_NOT_PENDING_DELAY (3)
#define RTC_TEST_ALARM_TEST_PENDING_DELAY (10)
#define RTC_TEST_ALARM_TIME_MINUTE (30)
#define RTC_TEST_ALARM_TIME_HOUR (13)
static const struct device *rtc = DEVICE_DT_GET(DT_ALIAS(rtc));
static const uint16_t alarms_count = DT_PROP(DT_ALIAS(rtc), alarms_count);
ZTEST(rtc_api, test_alarm)
{
int ret;
time_t timer_set;
struct rtc_time time_set;
struct rtc_time alarm_time_set;
uint16_t alarm_time_mask_supported;
uint16_t alarm_time_mask_set;
struct rtc_time alarm_time_get;
uint16_t alarm_time_mask_get;
/* Clear alarm alarm time */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_time(rtc, i, 0, NULL);
zassert_ok(ret, "Failed to clear alarm time");
}
/* Disable alarm callback */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_callback(rtc, i, NULL, NULL);
zassert_true((ret == 0) || (ret == -ENOTSUP),
"Failed to clear and disable alarm callback");
}
/* Every supported alarm field should reject invalid values. */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported);
zassert_ok(ret, "Failed to get supported alarm fields");
alarm_time_set = (struct rtc_time) {
.tm_sec = 70,
.tm_min = 70,
.tm_hour = 25,
.tm_mday = 35,
.tm_mon = 15,
.tm_year = 8000,
.tm_wday = 8,
.tm_yday = 370,
.tm_nsec = INT32_MAX,
};
uint16_t masks[] = {RTC_ALARM_TIME_MASK_SECOND, RTC_ALARM_TIME_MASK_MINUTE,
RTC_ALARM_TIME_MASK_HOUR, RTC_ALARM_TIME_MASK_MONTHDAY,
RTC_ALARM_TIME_MASK_MONTH, RTC_ALARM_TIME_MASK_YEAR,
RTC_ALARM_TIME_MASK_WEEKDAY, RTC_ALARM_TIME_MASK_YEARDAY,
RTC_ALARM_TIME_MASK_NSEC};
ARRAY_FOR_EACH(masks, j)
{
if (masks[j] & alarm_time_mask_supported) {
ret = rtc_alarm_set_time(rtc, i, masks[j], &alarm_time_set);
zassert_equal(
-EINVAL, ret,
"%s: RTC should reject invalid alarm time in field %zu.",
rtc->name, j);
}
}
}
/* Validate alarms supported fields */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported);
zassert_ok(ret, "Failed to get supported alarm fields");
/* Skip test if alarm does not support the minute and hour fields */
if (((RTC_ALARM_TIME_MASK_MINUTE & alarm_time_mask_supported) == 0) ||
((RTC_TEST_ALARM_TIME_HOUR & alarm_time_mask_supported) == 0)) {
ztest_test_skip();
}
}
/* Set alarm time */
alarm_time_set.tm_min = RTC_TEST_ALARM_TIME_MINUTE;
alarm_time_set.tm_hour = RTC_TEST_ALARM_TIME_HOUR;
alarm_time_mask_set = (RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR);
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_time(rtc, i, alarm_time_mask_set, &alarm_time_set);
zassert_ok(ret, "Failed to set alarm time");
}
/* Validate alarm time */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_get_time(rtc, i, &alarm_time_mask_get, &alarm_time_get);
zassert_ok(ret, "Failed to set alarm time");
zassert_equal(alarm_time_mask_get, alarm_time_mask_set,
"Incorrect alarm time mask");
zassert_equal(alarm_time_get.tm_min, alarm_time_get.tm_min,
"Incorrect alarm time minute field");
zassert_equal(alarm_time_get.tm_hour, alarm_time_get.tm_hour,
"Incorrect alarm time hour field");
}
/* Initialize RTC time to set */
timer_set = RTC_TEST_ALARM_SET_TIME;
gmtime_r(&timer_set, (struct tm *)(&time_set));
time_set.tm_isdst = -1;
time_set.tm_nsec = 0;
for (uint8_t k = 0; k < 2; k++) {
/* Set RTC time */
ret = rtc_set_time(rtc, &time_set);
zassert_ok(ret, "Failed to set time");
/* Clear alarm pending status */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_is_pending(rtc, i);
zassert_true(ret > -1, "Failed to clear alarm pending status");
}
/* Wait before validating alarm pending status has not been set prematurely */
k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_NOT_PENDING_DELAY));
/* Validate alarm are not pending */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_is_pending(rtc, i);
zassert_ok(ret, "Alarm should not be pending");
}
/* Wait for alarm to trigger */
k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_PENDING_DELAY));
/* Validate alarm is pending */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_is_pending(rtc, i);
zassert_equal(ret, 1, "Alarm should be pending");
}
}
/* Disable and clear alarms */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_time(rtc, i, 0, NULL);
zassert_ok(ret, "Failed to disable alarm");
ret = rtc_alarm_is_pending(rtc, i);
zassert_true(ret > -1, "Failed to clear alarm pending state");
}
}