zephyr/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c
Bjarki Arge Andreasen 5343ae6817 tests: drivers: rtc: rtc_api: add config for alarm time mask
RTCs support a variety of combinations of alarm time fields, set
by the alarm time mask. Until now, alarm tests have selected
only the minute and hour fields, as these are always supported,
but some RTCs require setting every supported field when setting
the alarm time, while other RTCs don't support setting every field.

To support all RTCs in the test suite, a configuration has been
added which makes the alarm time mask configurable. Boards can now
define the specific alarm time mask they want to test within
their boards .conf files.

Additionally, the alarm tests have been refactored to not depend
on the time.h library to determine the struct rtc_time times to
set as these are constant, so they are now provided as const
structs instead.

Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
2024-06-28 20:58:22 -04:00

161 lines
4.5 KiB
C

/*
* Copyright (c) 2022 Bjarki Arge Andreasen
* Copyright (c) 2024 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/device.h>
#include <zephyr/drivers/rtc.h>
#include <zephyr/sys/atomic.h>
#define RTC_TEST_ALARM_TEST_NOT_CALLED_DELAY (3)
#define RTC_TEST_ALARM_TEST_CALLED_DELAY (10)
static const struct device *rtc = DEVICE_DT_GET(DT_ALIAS(rtc));
static const uint16_t alarms_count = DT_PROP(DT_ALIAS(rtc), alarms_count);
static uint32_t callback_user_data_odd = 0x4321;
static uint32_t callback_user_data_even = 0x1234;
static atomic_t callback_called_mask_odd;
static atomic_t callback_called_mask_even;
static const uint16_t test_alarm_time_mask_set = CONFIG_TEST_RTC_ALARM_TIME_MASK;
/* Fri Jan 01 2021 13:29:50 GMT+0000 */
static const struct rtc_time test_rtc_time_set = {
.tm_sec = 50,
.tm_min = 29,
.tm_hour = 13,
.tm_mday = 1,
.tm_mon = 0,
.tm_year = 121,
.tm_wday = 5,
.tm_yday = 1,
.tm_isdst = -1,
.tm_nsec = 0,
};
/* Fri Jan 01 2021 13:30:00 GMT+0000 */
static const struct rtc_time test_alarm_time_set = {
.tm_sec = 0,
.tm_min = 30,
.tm_hour = 13,
.tm_mday = 1,
.tm_mon = 0,
.tm_year = 121,
.tm_wday = 5,
.tm_yday = 1,
.tm_isdst = -1,
.tm_nsec = 0,
};
static void test_rtc_alarm_callback_handler_odd(const struct device *dev, uint16_t id,
void *user_data)
{
atomic_set_bit(&callback_called_mask_odd, id);
}
static void test_rtc_alarm_callback_handler_even(const struct device *dev, uint16_t id,
void *user_data)
{
atomic_set_bit(&callback_called_mask_even, id);
}
ZTEST(rtc_api, test_alarm_callback)
{
int ret;
atomic_val_t callback_called_mask_status_odd;
atomic_val_t callback_called_mask_status_even;
bool callback_called_status;
/* Disable alarm callback */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_callback(rtc, i, NULL, NULL);
if (ret == -ENOTSUP) {
TC_PRINT("Alarm callbacks not supported\n");
ztest_test_skip();
} else {
zassert_ok(ret, "Failed to clear and disable alarm %d", i);
}
}
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_time(rtc, i, test_alarm_time_mask_set, &test_alarm_time_set);
zassert_ok(ret, "Failed to set alarm %d time", i);
}
/* Set RTC time */
ret = rtc_set_time(rtc, &test_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 %d pending status", i);
}
/* Set and enable alarm callback */
for (uint16_t i = 0; i < alarms_count; i++) {
if (i % 2) {
ret = rtc_alarm_set_callback(rtc, i,
test_rtc_alarm_callback_handler_odd,
&callback_user_data_odd);
} else {
ret = rtc_alarm_set_callback(rtc, i,
test_rtc_alarm_callback_handler_even,
&callback_user_data_even);
}
zassert_ok(ret, "Failed to set alarm %d callback", i);
}
for (uint8_t i = 0; i < 2; i++) {
/* Clear callback called atomics */
atomic_set(&callback_called_mask_odd, 0);
atomic_set(&callback_called_mask_even, 0);
/* Wait before validating alarm callbacks have not been called prematurely */
k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_NOT_CALLED_DELAY));
/* Validate alarm callbacks have not been called prematurely */
callback_called_mask_status_odd = atomic_get(&callback_called_mask_odd);
callback_called_mask_status_even = atomic_get(&callback_called_mask_even);
zassert_equal(callback_called_mask_status_odd, 0,
"Alarm callback called prematurely");
zassert_equal(callback_called_mask_status_even, 0,
"Alarm callback called prematurely");
/* Wait for alarm to trigger */
k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_CALLED_DELAY));
/* Validate alarm callback called */
for (uint16_t j = 0; j < alarms_count; j++) {
callback_called_status =
(j % 2) ? atomic_test_bit(&callback_called_mask_odd, j)
: atomic_test_bit(&callback_called_mask_even, j);
zassert_equal(callback_called_status, true,
"Alarm %d callback should have been called", j);
}
/* Reset RTC time */
ret = rtc_set_time(rtc, &test_rtc_time_set);
zassert_ok(ret, "Failed to set time");
}
/* Disable and clear alarms */
for (uint16_t i = 0; i < alarms_count; i++) {
ret = rtc_alarm_set_callback(rtc, i, NULL, NULL);
zassert_ok(ret, "Failed to disable alarm %d callback", i);
ret = rtc_alarm_set_time(rtc, i, 0, NULL);
zassert_ok(ret, "Failed to disable alarm %d", i);
ret = rtc_alarm_is_pending(rtc, i);
zassert_true(ret > -1, "Failed to clear alarm %d pending state", i);
}
}