1 /*
2  * Copyright (c) 2022 Bjarki Arge Andreasen
3  * Copyright (c) 2024 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/ztest.h>
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/rtc.h>
11 #include <zephyr/sys/atomic.h>
12 #include <zephyr/sys/util.h>
13 
14 #define RTC_TEST_ALARM_TEST_NOT_PENDING_DELAY (3)
15 #define RTC_TEST_ALARM_TEST_PENDING_DELAY     (10)
16 
17 static const struct device *rtc = DEVICE_DT_GET(DT_ALIAS(rtc));
18 static const uint16_t alarms_count = DT_PROP(DT_ALIAS(rtc), alarms_count);
19 static const uint16_t test_alarm_time_mask_set = CONFIG_TEST_RTC_ALARM_TIME_MASK;
20 
21 /* Fri Jan 01 2021 13:29:50 GMT+0000 */
22 static const struct rtc_time test_rtc_time_set = {
23 	.tm_sec = 50,
24 	.tm_min = 29,
25 	.tm_hour = 13,
26 	.tm_mday = 1,
27 	.tm_mon = 0,
28 	.tm_year = 121,
29 	.tm_wday = 5,
30 	.tm_yday = 1,
31 	.tm_isdst = -1,
32 	.tm_nsec = 0,
33 };
34 
35 /* Fri Jan 01 2021 13:30:00 GMT+0000 */
36 static const struct rtc_time test_alarm_time_set = {
37 	.tm_sec = 0,
38 	.tm_min = 30,
39 	.tm_hour = 13,
40 	.tm_mday = 1,
41 	.tm_mon = 0,
42 	.tm_year = 121,
43 	.tm_wday = 5,
44 	.tm_yday = 1,
45 	.tm_isdst = -1,
46 	.tm_nsec = 0,
47 };
48 
49 static const struct rtc_time test_alarm_time_invalid = {
50 	.tm_sec = 70,
51 	.tm_min = 70,
52 	.tm_hour = 25,
53 	.tm_mday = 35,
54 	.tm_mon = 15,
55 	.tm_year = 8000,
56 	.tm_wday = 8,
57 	.tm_yday = 370,
58 	.tm_nsec = INT32_MAX,
59 };
60 
61 static const uint16_t test_alarm_time_masks[] = {
62 	RTC_ALARM_TIME_MASK_SECOND,  RTC_ALARM_TIME_MASK_MINUTE,
63 	RTC_ALARM_TIME_MASK_HOUR,    RTC_ALARM_TIME_MASK_MONTHDAY,
64 	RTC_ALARM_TIME_MASK_MONTH,   RTC_ALARM_TIME_MASK_YEAR,
65 	RTC_ALARM_TIME_MASK_WEEKDAY, RTC_ALARM_TIME_MASK_YEARDAY,
66 	RTC_ALARM_TIME_MASK_NSEC
67 };
68 
ZTEST(rtc_api,test_alarm)69 ZTEST(rtc_api, test_alarm)
70 {
71 	int ret;
72 	uint16_t alarm_time_mask_supported;
73 	struct rtc_time alarm_time_get;
74 	uint16_t alarm_time_mask_get;
75 
76 	/* Clear alarm alarm time */
77 	for (uint16_t i = 0; i < alarms_count; i++) {
78 		ret = rtc_alarm_set_time(rtc, i, 0, NULL);
79 
80 		zassert_ok(ret, "Failed to clear alarm %d time", i);
81 	}
82 
83 	/* Disable alarm callback */
84 	for (uint16_t i = 0; i < alarms_count; i++) {
85 		ret = rtc_alarm_set_callback(rtc, i, NULL, NULL);
86 
87 		zassert_true((ret == 0) || (ret == -ENOTSUP),
88 			     "Failed to clear and disable alarm %d callback", i);
89 	}
90 
91 	/* Every supported alarm field should reject invalid values. */
92 	for (uint16_t i = 0; i < alarms_count; i++) {
93 		ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported);
94 		zassert_ok(ret, "Failed to get supported alarm %d fields", i);
95 
96 		ARRAY_FOR_EACH(test_alarm_time_masks, j)
97 		{
98 			if (test_alarm_time_masks[j] & alarm_time_mask_supported) {
99 				ret = rtc_alarm_set_time(rtc, i, test_alarm_time_masks[j],
100 							 &test_alarm_time_invalid);
101 				zassert_equal(
102 					-EINVAL, ret,
103 					"%s: RTC should reject invalid alarm %d time in field %zu.",
104 					rtc->name, i, j);
105 			}
106 		}
107 	}
108 
109 	/* Validate alarms supported fields */
110 	for (uint16_t i = 0; i < alarms_count; i++) {
111 		ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported);
112 		zassert_ok(ret, "Failed to get supported alarm %d fields", i);
113 
114 		ret = (test_alarm_time_mask_set & (~alarm_time_mask_supported)) ? -EINVAL : 0;
115 		zassert_ok(ret, "Configured alarm time fields to set are not supported");
116 	}
117 
118 	for (uint16_t i = 0; i < alarms_count; i++) {
119 		ret = rtc_alarm_set_time(rtc, i, test_alarm_time_mask_set, &test_alarm_time_set);
120 		zassert_ok(ret, "Failed to set alarm %d time", i);
121 	}
122 
123 	/* Validate alarm time */
124 	for (uint16_t i = 0; i < alarms_count; i++) {
125 		ret = rtc_alarm_get_time(rtc, i, &alarm_time_mask_get, &alarm_time_get);
126 		zassert_ok(ret, "Failed to set alarm %d time", i);
127 
128 		zassert_equal(alarm_time_mask_get, test_alarm_time_mask_set,
129 			      "Incorrect alarm %d time mask", i);
130 
131 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_SECOND) {
132 			zassert_equal(alarm_time_get.tm_sec, test_alarm_time_set.tm_sec,
133 				      "Incorrect alarm %d tm_sec field", i);
134 		}
135 
136 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_MINUTE) {
137 			zassert_equal(alarm_time_get.tm_min, test_alarm_time_set.tm_min,
138 				      "Incorrect alarm %d tm_min field", i);
139 		}
140 
141 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_HOUR) {
142 			zassert_equal(alarm_time_get.tm_hour, test_alarm_time_set.tm_hour,
143 				      "Incorrect alarm %d tm_hour field", i);
144 		}
145 
146 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_MONTHDAY) {
147 			zassert_equal(alarm_time_get.tm_mday, test_alarm_time_set.tm_mday,
148 				      "Incorrect alarm %d tm_mday field", i);
149 		}
150 
151 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_MONTH) {
152 			zassert_equal(alarm_time_get.tm_mon, test_alarm_time_set.tm_mon,
153 				      "Incorrect alarm %d tm_mon field", i);
154 		}
155 
156 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_YEAR) {
157 			zassert_equal(alarm_time_get.tm_year, test_alarm_time_set.tm_year,
158 				      "Incorrect alarm %d tm_year field", i);
159 		}
160 
161 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_WEEKDAY) {
162 			zassert_equal(alarm_time_get.tm_wday, test_alarm_time_set.tm_wday,
163 				      "Incorrect alarm %d tm_wday field", i);
164 		}
165 
166 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_YEARDAY) {
167 			zassert_equal(alarm_time_get.tm_yday, test_alarm_time_set.tm_yday,
168 				      "Incorrect alarm %d tm_yday field", i);
169 		}
170 
171 		if (test_alarm_time_mask_set & RTC_ALARM_TIME_MASK_NSEC) {
172 			zassert_equal(alarm_time_get.tm_nsec, test_alarm_time_set.tm_nsec,
173 				      "Incorrect alarm %d tm_nsec field", i);
174 		}
175 	}
176 
177 	for (uint8_t k = 0; k < 2; k++) {
178 		/* Set RTC time */
179 		ret = rtc_set_time(rtc, &test_rtc_time_set);
180 		zassert_ok(ret, "Failed to set time");
181 
182 		/* Clear alarm pending status */
183 		for (uint16_t i = 0; i < alarms_count; i++) {
184 			ret = rtc_alarm_is_pending(rtc, i);
185 			zassert_true(ret > -1, "Failed to clear alarm %d pending status", i);
186 		}
187 
188 		/* Wait before validating alarm pending status has not been set prematurely */
189 		k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_NOT_PENDING_DELAY));
190 
191 		/* Validate alarm are not pending */
192 		for (uint16_t i = 0; i < alarms_count; i++) {
193 			ret = rtc_alarm_is_pending(rtc, i);
194 			zassert_ok(ret, "Alarm %d should not be pending", i);
195 		}
196 
197 		/* Wait for alarm to trigger */
198 		k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_PENDING_DELAY));
199 
200 		/* Validate alarm is pending */
201 		for (uint16_t i = 0; i < alarms_count; i++) {
202 			ret = rtc_alarm_is_pending(rtc, i);
203 			zassert_equal(ret, 1, "Alarm %d should be pending", i);
204 		}
205 	}
206 
207 	/* Disable and clear alarms */
208 	for (uint16_t i = 0; i < alarms_count; i++) {
209 		ret = rtc_alarm_set_time(rtc, i, 0, NULL);
210 		zassert_ok(ret, "Failed to disable alarm %d", i);
211 
212 		ret = rtc_alarm_is_pending(rtc, i);
213 		zassert_true(ret > -1, "Failed to clear alarm %d pending state", i);
214 	}
215 }
216