blob: 9dfa73eaaceeab5eb7cff2a3aa564ca56ca3b456 [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 <time.h>
/* Fri Jan 01 2021 13:29:50 GMT+0000 */
#define RTC_TEST_ALARM_SET_TIME (1609507790)
#define RTC_TEST_ALARM_TEST_NOT_CALLED_DELAY (3)
#define RTC_TEST_ALARM_TEST_CALLED_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);
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 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;
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;
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);
zassert_true(ret == 0, "Failed to clear and disable alarm");
}
/* 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_true(ret == 0, "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_true(ret == 0, "Failed to set alarm time");
}
/* 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;
/* Set RTC time */
ret = rtc_set_time(rtc, &time_set);
zassert_true(ret == 0, "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");
}
/* 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_true(ret == 0, "Failed to set alarm callback");
}
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_true(callback_called_mask_status_odd == 0,
"Alarm callback called prematurely");
zassert_true(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 i = 0; i < alarms_count; i++) {
callback_called_status =
(i % 2) ? atomic_test_bit(&callback_called_mask_odd, i)
: atomic_test_bit(&callback_called_mask_even, i);
zassert_true(callback_called_status == true,
"Alarm callback should have been called");
}
/* Reset RTC time */
ret = rtc_set_time(rtc, &time_set);
zassert_true(ret == 0, "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_true(ret == 0, "Failed to disable alarm callback");
ret = rtc_alarm_set_time(rtc, i, 0, NULL);
zassert_true(ret == 0, "Failed to disable alarm");
ret = rtc_alarm_is_pending(rtc, i);
zassert_true(ret > -1, "Failed to clear alarm pending state");
}
}