1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdlib.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/types.h>
10
11 struct timer_data {
12 int expire_cnt;
13 int stop_cnt;
14 int64_t timestamp;
15 };
16
17 #define DURATION 100
18 #define PERIOD 50
19 #define EXPIRE_TIMES 4
20 #define WITHIN_ERROR(var, target, epsilon) (llabs((int64_t) ((target) - (var))) <= (epsilon))
21
22 /* ms can be converted precisely to ticks only when a ms is exactly
23 * represented by an integral number of ticks. If the conversion is
24 * not precise, then the reverse conversion of a difference in ms can
25 * end up being off by a tick depending on the relative error between
26 * the first and second ms conversion, and we need to adjust the
27 * tolerance interval.
28 */
29 #define INEXACT_MS_CONVERT ((CONFIG_SYS_CLOCK_TICKS_PER_SEC % MSEC_PER_SEC) != 0)
30
31 #if CONFIG_NRF_RTC_TIMER
32 /* On Nordic SOCs one or both of the tick and busy-wait clocks may
33 * derive from sources that have slews that sum to +/- 13%.
34 */
35 #define BUSY_TICK_SLEW_PPM 130000U
36 #else
37 /* On other platforms assume the clocks are perfectly aligned. */
38 #define BUSY_TICK_SLEW_PPM 0U
39 #endif
40 #define PPM_DIVISOR 1000000U
41
42 /* If the tick clock is faster or slower than the busywait clock the
43 * remaining time for a partially elapsed timer in ticks will be
44 * larger or smaller than expected by a value that depends on the slew
45 * between the two clocks. Produce a maximum error for a given
46 * duration in microseconds.
47 */
48 #define BUSY_SLEW_THRESHOLD_TICKS(_us) \
49 k_us_to_ticks_ceil32((_us) * (uint64_t)BUSY_TICK_SLEW_PPM \
50 / PPM_DIVISOR)
51
52 static void duration_expire(struct k_timer *timer);
53 static void duration_stop(struct k_timer *timer);
54
55 /** TESTPOINT: init timer via K_TIMER_DEFINE */
56 K_TIMER_DEFINE(ktimer, duration_expire, duration_stop);
57
58 static struct k_timer duration_timer;
59 static struct k_timer period0_timer;
60 static struct k_timer expire_timer;
61 static struct k_timer sync_timer;
62 static struct k_timer periodicity_timer;
63 static struct k_timer status_timer;
64 static struct k_timer status_anytime_timer;
65 static struct k_timer status_sync_timer;
66 static struct k_timer remain_timer;
67
68 static ZTEST_BMEM struct timer_data tdata;
69
70 #define TIMER_ASSERT(exp, tmr) \
71 do { \
72 if (!(exp)) { \
73 k_timer_stop(tmr); \
74 zassert_true(exp); \
75 } \
76 } while (0)
77
init_timer_data(void)78 static void init_timer_data(void)
79 {
80 tdata.expire_cnt = 0;
81 tdata.stop_cnt = 0;
82
83 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
84 k_usleep(1); /* align to tick */
85 }
86
87 tdata.timestamp = k_uptime_get();
88 }
89
interval_check(int64_t interval,int64_t desired)90 static bool interval_check(int64_t interval, int64_t desired)
91 {
92 int64_t slop = INEXACT_MS_CONVERT ? 1 : 0;
93
94 /* Tickless kernels will advance time inside of an ISR, so it
95 * is always possible (especially with high tick rates and
96 * slow CPUs) for us to arrive at the uptime check above too
97 * late to see a full period elapse before the next period.
98 * We can alias at both sides of the interval, so two
99 * one-ticks deltas (NOT one two-tick delta!)
100 */
101 if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
102 slop += 2 * k_ticks_to_ms_ceil32(1);
103 }
104
105 if (!WITHIN_ERROR(interval, desired, slop)) {
106 return false;
107 }
108
109 return true;
110 }
111
112 /* entry routines */
duration_expire(struct k_timer * timer)113 static void duration_expire(struct k_timer *timer)
114 {
115 /** TESTPOINT: expire function */
116 int64_t interval = k_uptime_delta(&tdata.timestamp);
117
118 tdata.expire_cnt++;
119 if (tdata.expire_cnt == 1) {
120 TIMER_ASSERT(interval_check(interval, DURATION), timer);
121 } else {
122 TIMER_ASSERT(interval_check(interval, PERIOD), timer);
123 }
124
125 if (tdata.expire_cnt >= EXPIRE_TIMES) {
126 k_timer_stop(timer);
127 }
128 }
129
duration_stop(struct k_timer * timer)130 static void duration_stop(struct k_timer *timer)
131 {
132 tdata.stop_cnt++;
133 }
134
period0_expire(struct k_timer * timer)135 static void period0_expire(struct k_timer *timer)
136 {
137 tdata.expire_cnt++;
138 }
139
status_expire(struct k_timer * timer)140 static void status_expire(struct k_timer *timer)
141 {
142 /** TESTPOINT: status get upon timer expired */
143 TIMER_ASSERT(k_timer_status_get(timer) == 1, timer);
144 /** TESTPOINT: remaining get upon timer expired */
145 TIMER_ASSERT(k_timer_remaining_get(timer) >= PERIOD, timer);
146
147 if (tdata.expire_cnt >= EXPIRE_TIMES) {
148 k_timer_stop(timer);
149 }
150 }
151
busy_wait_ms(int32_t ms)152 static void busy_wait_ms(int32_t ms)
153 {
154 k_busy_wait(ms*1000);
155 }
156
status_stop(struct k_timer * timer)157 static void status_stop(struct k_timer *timer)
158 {
159 /** TESTPOINT: remaining get upon timer stopped */
160 TIMER_ASSERT(k_timer_remaining_get(timer) == 0, timer);
161 }
162
163 /**
164 * @brief Tests for the Timer kernel object
165 * @defgroup kernel_timer_tests Timer
166 * @ingroup all_tests
167 * @{
168 * @}
169 */
170
171 /**
172 * @brief Test duration and period of Timer
173 *
174 * Validates initial duration and period of timer.
175 *
176 * It initializes the timer with k_timer_init(), then starts the timer
177 * using k_timer_start() with specific initial duration and period.
178 * Stops the timer using k_timer_stop() and checks for proper completion
179 * of duration and period.
180 *
181 * @ingroup kernel_timer_tests
182 *
183 * @see k_timer_init(), k_timer_start(), k_timer_stop(), k_uptime_get(),
184 * k_busy_wait()
185 */
ZTEST_USER(timer_api,test_timer_duration_period)186 ZTEST_USER(timer_api, test_timer_duration_period)
187 {
188 init_timer_data();
189 /** TESTPOINT: init timer via k_timer_init */
190 k_timer_start(&duration_timer, K_MSEC(DURATION), K_MSEC(PERIOD));
191 busy_wait_ms(DURATION + PERIOD * EXPIRE_TIMES + PERIOD / 2);
192 /** TESTPOINT: check expire and stop times */
193 TIMER_ASSERT(tdata.expire_cnt == EXPIRE_TIMES, &duration_timer);
194 TIMER_ASSERT(tdata.stop_cnt == 1, &duration_timer);
195
196 k_timer_start(&duration_timer, K_FOREVER, K_MSEC(PERIOD));
197 TIMER_ASSERT(tdata.stop_cnt == 1, &duration_timer);
198 /* cleanup environment */
199 k_timer_stop(&duration_timer);
200 }
201
202 /**
203 *
204 * @brief Test restart the timer
205 *
206 * @details Validates initial duration and period of timer. Start the timer with
207 * specific duration and period. Then starts the timer again, and check
208 * the status of timer.
209 *
210 * @ingroup kernel_timer_tests
211 *
212 * @see k_timer_init(), k_timer_start(), k_timer_stop, k_uptime_get(),
213 * k_busy_wait()
214 *
215 */
ZTEST_USER(timer_api,test_timer_restart)216 ZTEST_USER(timer_api, test_timer_restart)
217 {
218 init_timer_data();
219 k_timer_start(&status_anytime_timer, K_MSEC(DURATION),
220 K_MSEC(PERIOD));
221 busy_wait_ms(DURATION + PERIOD * (EXPIRE_TIMES - 1) + PERIOD / 2);
222
223 /** TESTPOINT: restart the timer */
224 k_timer_start(&status_anytime_timer, K_MSEC(DURATION),
225 K_MSEC(PERIOD));
226 /* Restart timer, timer's status is reset to zero */
227 TIMER_ASSERT(k_timer_status_get(&status_anytime_timer) == 0,
228 &status_anytime_timer);
229
230 /* cleanup environment */
231 k_timer_stop(&status_anytime_timer);
232 }
233
234
235 /**
236 * @brief Test Timer with zero period value
237 *
238 * Validates initial timer duration, keeping timer period to zero.
239 * Basically, acting as one-shot timer.
240 * It initializes the timer with k_timer_init(), then starts the timer
241 * using k_timer_start() with specific initial duration and period as
242 * zero. Stops the timer using k_timer_stop() and checks for proper
243 * completion.
244 *
245 * @ingroup kernel_timer_tests
246 *
247 * @see k_timer_init(), k_timer_start(), k_timer_stop(), k_uptime_get(),
248 * k_busy_wait()
249 */
ZTEST_USER(timer_api,test_timer_period_0)250 ZTEST_USER(timer_api, test_timer_period_0)
251 {
252 init_timer_data();
253 /** TESTPOINT: set period 0 */
254 k_timer_start(&period0_timer,
255 K_TICKS(k_ms_to_ticks_floor32(DURATION)
256 - BUSY_SLEW_THRESHOLD_TICKS(DURATION
257 * USEC_PER_MSEC)),
258 K_NO_WAIT);
259 /* Need to wait at least 2 durations to ensure one-shot behavior. */
260 busy_wait_ms(2 * DURATION + 1);
261
262 /** TESTPOINT: ensure it is one-shot timer */
263 TIMER_ASSERT((tdata.expire_cnt == 1)
264 || (INEXACT_MS_CONVERT
265 && (tdata.expire_cnt == 0)), &period0_timer);
266 TIMER_ASSERT(tdata.stop_cnt == 0, &period0_timer);
267
268 /* cleanup environment */
269 k_timer_stop(&period0_timer);
270 }
271
272 /**
273 * @brief Test Timer with K_FOREVER period value
274 *
275 * Validates initial timer duration, keeping timer period to K_FOREVER.
276 * Basically, acting as one-shot timer.
277 * It initializes the timer with k_timer_init(), then starts the timer
278 * using k_timer_start() with specific initial duration and period as
279 * zero. Stops the timer using k_timer_stop() and checks for proper
280 * completion.
281 *
282 * @ingroup kernel_timer_tests
283 *
284 * @see k_timer_init(), k_timer_start(), k_timer_stop(), k_uptime_get(),
285 * k_busy_wait()
286 */
ZTEST_USER(timer_api,test_timer_period_k_forever)287 ZTEST_USER(timer_api, test_timer_period_k_forever)
288 {
289 init_timer_data();
290 /** TESTPOINT: set period 0 */
291 k_timer_start(
292 &period0_timer,
293 K_TICKS(k_ms_to_ticks_floor32(DURATION) -
294 BUSY_SLEW_THRESHOLD_TICKS(DURATION * USEC_PER_MSEC)),
295 K_FOREVER);
296 tdata.timestamp = k_uptime_get();
297
298 /* Need to wait at least 2 durations to ensure one-shot behavior. */
299 busy_wait_ms(2 * DURATION + 1);
300
301 /** TESTPOINT: ensure it is one-shot timer */
302 TIMER_ASSERT((tdata.expire_cnt == 1) ||
303 (INEXACT_MS_CONVERT && (tdata.expire_cnt == 0)),
304 &period0_timer);
305 TIMER_ASSERT(tdata.stop_cnt == 0, &period0_timer);
306
307 /* cleanup environment */
308 k_timer_stop(&period0_timer);
309 }
310
311 /**
312 * @brief Test Timer without any timer expiry callback function
313 *
314 * Validates timer without any expiry_fn(set to NULL). expiry_fn() is a
315 * function that is invoked each time the timer expires.
316 *
317 * It initializes the timer with k_timer_init(), then starts the timer
318 * using k_timer_start(). Stops the timer using k_timer_stop() and
319 * checks for expire_cnt to zero, as expiry_fn was not defined at all.
320 *
321 * @ingroup kernel_timer_tests
322 *
323 * @see k_timer_init(), k_timer_start(), k_timer_stop(), k_uptime_get(),
324 * k_busy_wait()
325 */
ZTEST_USER(timer_api,test_timer_expirefn_null)326 ZTEST_USER(timer_api, test_timer_expirefn_null)
327 {
328 init_timer_data();
329 /** TESTPOINT: expire function NULL */
330 k_timer_start(&expire_timer, K_MSEC(DURATION), K_MSEC(PERIOD));
331 busy_wait_ms(DURATION + PERIOD * EXPIRE_TIMES + PERIOD / 2);
332
333 k_timer_stop(&expire_timer);
334 /** TESTPOINT: expire handler is not invoked */
335 TIMER_ASSERT(tdata.expire_cnt == 0, &expire_timer);
336 /** TESTPOINT: stop handler is invoked */
337 TIMER_ASSERT(tdata.stop_cnt == 1, &expire_timer);
338
339 /* cleanup environment */
340 k_timer_stop(&expire_timer);
341 }
342
343 /* Wait for the next expiration of an OS timer tick, to synchronize
344 * test start
345 */
tick_sync(void)346 static void tick_sync(void)
347 {
348 k_timer_start(&sync_timer, K_NO_WAIT, K_MSEC(1));
349 k_timer_status_sync(&sync_timer);
350 k_timer_stop(&sync_timer);
351 }
352
353 /**
354 * @brief Test to check timer periodicity
355 *
356 * Timer test to check for the predictability with which the timer
357 * expires depending on the period configured.
358 *
359 * It initializes the timer with k_timer_init(), then starts the timer
360 * using k_timer_start() with specific period. It resets the timer’s
361 * status to zero with k_timer_status_sync and identifies the delta
362 * between each timer expiry to check for the timer expiration period
363 * correctness. Finally, stops the timer using k_timer_stop().
364 *
365 * @ingroup kernel_timer_tests
366 *
367 * @see k_timer_init(), k_timer_start(), k_timer_status_sync(),
368 * k_timer_stop(), k_uptime_get(), k_uptime_delta()
369 */
ZTEST_USER(timer_api,test_timer_periodicity)370 ZTEST_USER(timer_api, test_timer_periodicity)
371 {
372 uint64_t period_ms = k_ticks_to_ms_floor64(k_ms_to_ticks_ceil32(PERIOD));
373 int64_t delta;
374
375 /* Start at a tick boundary, otherwise a tick expiring between
376 * the unlocked (and unlockable) start/uptime/sync steps below
377 * will throw off the math.
378 */
379 tick_sync();
380
381 init_timer_data();
382 /** TESTPOINT: set duration 0 */
383 k_timer_start(&periodicity_timer, K_NO_WAIT, K_MSEC(PERIOD));
384
385 /* clear the expiration that would have happened due to
386 * whatever duration that was set. Since timer is likely
387 * to fire before call to k_timer_status_sync(), we have
388 * to synchronize twice to ensure that the timestamp will
389 * be fetched as soon as possible after timer firing.
390 */
391 k_timer_status_sync(&periodicity_timer);
392 k_timer_status_sync(&periodicity_timer);
393 tdata.timestamp = k_uptime_get();
394
395 for (int i = 0; i < EXPIRE_TIMES; i++) {
396 /** TESTPOINT: expired times returned by status sync */
397 TIMER_ASSERT(k_timer_status_sync(&periodicity_timer) == 1,
398 &periodicity_timer);
399
400 delta = k_uptime_delta(&tdata.timestamp);
401
402 /** TESTPOINT: check if timer fired within 1ms of the
403 * expected period (firing time).
404 *
405 * Please note, that expected firing time is not the
406 * one requested, as the kernel uses the ticks to manage
407 * time. The actual period will be equal to [tick time]
408 * multiplied by k_ms_to_ticks_ceil32(PERIOD).
409 *
410 * In the case of inexact conversion the delta will
411 * occasionally be one less than the expected number.
412 */
413 TIMER_ASSERT(WITHIN_ERROR(delta, period_ms, 1)
414 || (INEXACT_MS_CONVERT
415 && (delta == period_ms - 1)),
416 &periodicity_timer);
417 }
418
419 /* cleanup environment */
420 k_timer_stop(&periodicity_timer);
421 }
422
423 /**
424 * @brief Test Timer status and time remaining before next expiry
425 *
426 * Timer test to validate timer status and next trigger expiry time
427 *
428 * It initializes the timer with k_timer_init(), then starts the timer
429 * using k_timer_start() and checks for timer current status with
430 * k_timer_status_get() and remaining time before next expiry using
431 * k_timer_remaining_get(). Stops the timer using k_timer_stop().
432 *
433 * @ingroup kernel_timer_tests
434 *
435 * @see k_timer_init(), k_timer_start(), k_timer_status_get(),
436 * k_timer_remaining_get(), k_timer_stop()
437 */
ZTEST_USER(timer_api,test_timer_status_get)438 ZTEST_USER(timer_api, test_timer_status_get)
439 {
440 init_timer_data();
441 k_timer_start(&status_timer, K_MSEC(DURATION), K_MSEC(PERIOD));
442 /** TESTPOINT: status get upon timer starts */
443 TIMER_ASSERT(k_timer_status_get(&status_timer) == 0, &status_timer);
444 /** TESTPOINT: remaining get upon timer starts */
445 TIMER_ASSERT(k_timer_remaining_get(&status_timer) >= DURATION / 2,
446 &status_timer);
447
448 /* cleanup environment */
449 k_timer_stop(&status_timer);
450 }
451
452 /**
453 * @brief Test Timer status randomly after certain duration
454 *
455 * Validate timer status function using k_timer_status_get().
456 *
457 * It initializes the timer with k_timer_init(), then starts the timer
458 * using k_timer_start() with specific initial duration and period.
459 * Checks for timer status randomly after certain duration.
460 * Stops the timer using k_timer_stop().
461 *
462 * @ingroup kernel_timer_tests
463 *
464 * @see k_timer_init(), k_timer_start(), k_timer_status_get(),
465 * k_timer_stop(), k_busy_wait()
466 */
ZTEST_USER(timer_api,test_timer_status_get_anytime)467 ZTEST_USER(timer_api, test_timer_status_get_anytime)
468 {
469 init_timer_data();
470 k_timer_start(&status_anytime_timer, K_MSEC(DURATION),
471 K_MSEC(PERIOD));
472 busy_wait_ms(DURATION + PERIOD * (EXPIRE_TIMES - 1) + PERIOD / 2);
473
474 /** TESTPOINT: status get at any time */
475 TIMER_ASSERT(k_timer_status_get(&status_anytime_timer) == EXPIRE_TIMES,
476 &status_anytime_timer);
477 busy_wait_ms(PERIOD);
478 TIMER_ASSERT(k_timer_status_get(&status_anytime_timer) == 1,
479 &status_anytime_timer);
480
481 /* cleanup environment */
482 k_timer_stop(&status_anytime_timer);
483 }
484
485 /**
486 * @brief Test Timer thread synchronization
487 *
488 * Validate thread synchronization by blocking the calling thread until
489 * the timer expires.
490 *
491 * It initializes the timer with k_timer_init(), then starts the timer
492 * using k_timer_start() and checks timer status with
493 * k_timer_status_sync() for thread synchronization with expiry count.
494 * Stops the timer using k_timer_stop.
495 *
496 * @ingroup kernel_timer_tests
497 *
498 * @see k_timer_init(), k_timer_start(), k_timer_status_sync(),
499 * k_timer_stop()
500 */
ZTEST_USER(timer_api,test_timer_status_sync)501 ZTEST_USER(timer_api, test_timer_status_sync)
502 {
503 init_timer_data();
504 k_timer_start(&status_sync_timer, K_MSEC(DURATION), K_MSEC(PERIOD));
505
506 for (int i = 0; i < EXPIRE_TIMES; i++) {
507 /** TESTPOINT: check timer not expire */
508 TIMER_ASSERT(tdata.expire_cnt == i, &status_sync_timer);
509 /** TESTPOINT: expired times returned by status sync */
510 TIMER_ASSERT(k_timer_status_sync(&status_sync_timer) == 1,
511 &status_sync_timer);
512 /** TESTPOINT: check timer not expire */
513 TIMER_ASSERT(tdata.expire_cnt == (i + 1), &status_sync_timer);
514 }
515
516 init_timer_data();
517 k_timer_start(&status_sync_timer, K_MSEC(DURATION), K_MSEC(PERIOD));
518 busy_wait_ms(PERIOD*2);
519 zassert_true(k_timer_status_sync(&status_sync_timer));
520
521 /* cleanup environment */
522 k_timer_stop(&status_sync_timer);
523 zassert_false(k_timer_status_sync(&status_sync_timer));
524 }
525
526 /**
527 * @brief Test statically defined Timer init
528 *
529 * Validate statically defined timer init using K_TIMER_DEFINE
530 *
531 * It creates prototype of K_TIMER_DEFINE to statically define timer
532 * init and starts the timer with k_timer_start() with specific initial
533 * duration and period. Stops the timer using k_timer_stop() and checks
534 * for proper completion of duration and period.
535 *
536 * @ingroup kernel_timer_tests
537 *
538 * @see k_timer_start(), K_TIMER_DEFINE(), k_timer_stop()
539 * k_uptime_get(), k_busy_wait()
540 */
ZTEST_USER(timer_api,test_timer_k_define)541 ZTEST_USER(timer_api, test_timer_k_define)
542 {
543 init_timer_data();
544 /** TESTPOINT: init timer via k_timer_init */
545 k_timer_start(&ktimer, K_MSEC(DURATION), K_MSEC(PERIOD));
546 busy_wait_ms(DURATION + PERIOD * EXPIRE_TIMES + PERIOD / 2);
547
548 /** TESTPOINT: check expire and stop times */
549 TIMER_ASSERT(tdata.expire_cnt == EXPIRE_TIMES, &ktimer);
550 TIMER_ASSERT(tdata.stop_cnt == 1, &ktimer);
551
552 /* cleanup environment */
553 k_timer_stop(&ktimer);
554
555 init_timer_data();
556 /** TESTPOINT: init timer via k_timer_init */
557 k_timer_start(&ktimer, K_MSEC(DURATION), K_MSEC(PERIOD));
558
559 /* Call the k_timer_start() again to make sure that
560 * the initial timeout request gets cancelled and new
561 * one will get added.
562 */
563 busy_wait_ms(DURATION / 2);
564 k_timer_start(&ktimer, K_MSEC(DURATION), K_MSEC(PERIOD));
565 tdata.timestamp = k_uptime_get();
566 busy_wait_ms(DURATION + PERIOD * EXPIRE_TIMES + PERIOD / 2);
567
568 /** TESTPOINT: check expire and stop times */
569 TIMER_ASSERT(tdata.expire_cnt == EXPIRE_TIMES, &ktimer);
570 TIMER_ASSERT(tdata.stop_cnt == 1, &ktimer);
571
572 /* cleanup environment */
573 k_timer_stop(&ktimer);
574 }
575
576 static void user_data_timer_handler(struct k_timer *timer);
577
578 K_TIMER_DEFINE(timer0, user_data_timer_handler, NULL);
579 K_TIMER_DEFINE(timer1, user_data_timer_handler, NULL);
580 K_TIMER_DEFINE(timer2, user_data_timer_handler, NULL);
581 K_TIMER_DEFINE(timer3, user_data_timer_handler, NULL);
582 K_TIMER_DEFINE(timer4, user_data_timer_handler, NULL);
583
584 static ZTEST_DMEM struct k_timer *user_data_timer[5] = {
585 &timer0, &timer1, &timer2, &timer3, &timer4
586 };
587
588 static const intptr_t user_data[5] = { 0x1337, 0xbabe, 0xd00d, 0xdeaf, 0xfade };
589
590 static ZTEST_BMEM int user_data_correct[5];
591
user_data_timer_handler(struct k_timer * timer)592 static void user_data_timer_handler(struct k_timer *timer)
593 {
594 int timer_num = timer == user_data_timer[0] ? 0 :
595 timer == user_data_timer[1] ? 1 :
596 timer == user_data_timer[2] ? 2 :
597 timer == user_data_timer[3] ? 3 :
598 timer == user_data_timer[4] ? 4 : -1;
599
600 if (timer_num == -1) {
601 return;
602 }
603
604 intptr_t data_retrieved = (intptr_t)k_timer_user_data_get(timer);
605
606 user_data_correct[timer_num] = user_data[timer_num] == data_retrieved;
607 }
608
609 /**
610 * @brief Test user-specific data associated with timer
611 *
612 * Validate user-specific data associated with timer
613 *
614 * It creates prototype of K_TIMER_DEFINE and starts the timer using
615 * k_timer_start() with specific initial duration, along with associated
616 * user data using k_timer_user_data_set and k_timer_user_data_get().
617 * Stops the timer using k_timer_stop() and checks for correct data
618 * retrieval after timer completion.
619 *
620 * @ingroup kernel_timer_tests
621 *
622 * @see K_TIMER_DEFINE(), k_timer_user_data_set(), k_timer_start(),
623 * k_timer_user_data_get(), k_timer_stop()
624 */
ZTEST_USER(timer_api,test_timer_user_data)625 ZTEST_USER(timer_api, test_timer_user_data)
626 {
627 int ii;
628
629 for (ii = 0; ii < 5; ii++) {
630 intptr_t check;
631
632 k_timer_user_data_set(user_data_timer[ii],
633 (void *)user_data[ii]);
634 check = (intptr_t)k_timer_user_data_get(user_data_timer[ii]);
635
636 zassert_true(check == user_data[ii]);
637 }
638
639 for (ii = 0; ii < 5; ii++) {
640 k_timer_start(user_data_timer[ii], K_MSEC(50 + ii * 50),
641 K_NO_WAIT);
642 }
643
644 uint32_t wait_ms = 50 * ii + 50;
645
646 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
647 k_msleep(wait_ms);
648 } else {
649 uint32_t wait_us = 1000 * wait_ms;
650
651 k_busy_wait(wait_us + (wait_us * BUSY_TICK_SLEW_PPM) / PPM_DIVISOR);
652 }
653
654 for (ii = 0; ii < 5; ii++) {
655 k_timer_stop(user_data_timer[ii]);
656 }
657
658 for (ii = 0; ii < 5; ii++) {
659 zassert_true(user_data_correct[ii]);
660 }
661 }
662
663 /**
664 * @brief Test accuracy of k_timer_remaining_get()
665 *
666 * Validate countdown of time to expiration
667 *
668 * Starts a timer, busy-waits for half the DURATION, then checks the
669 * remaining time to expiration and stops the timer. The remaining time
670 * should reflect the passage of at least the busy-wait interval.
671 *
672 * @ingroup kernel_timer_tests
673 *
674 * @see k_timer_init(), k_timer_start(), k_timer_stop(),
675 * k_timer_remaining_get()
676 */
677
ZTEST_USER(timer_api,test_timer_remaining)678 ZTEST_USER(timer_api, test_timer_remaining)
679 {
680 uint32_t dur_ticks = k_ms_to_ticks_ceil32(DURATION);
681 uint32_t target_rem_ticks = k_ms_to_ticks_ceil32(DURATION / 2);
682 uint32_t rem_ms, rem_ticks, exp_ticks;
683 int32_t delta_ticks;
684 uint32_t slew_ticks;
685 uint64_t now;
686
687
688 init_timer_data();
689 k_timer_start(&remain_timer, K_MSEC(DURATION), K_NO_WAIT);
690 busy_wait_ms(DURATION / 2);
691 rem_ticks = k_timer_remaining_ticks(&remain_timer);
692 now = k_uptime_ticks();
693 rem_ms = k_timer_remaining_get(&remain_timer);
694 exp_ticks = k_timer_expires_ticks(&remain_timer);
695 k_timer_stop(&remain_timer);
696 TIMER_ASSERT(tdata.expire_cnt == 0, &remain_timer);
697 TIMER_ASSERT(tdata.stop_cnt == 1, &remain_timer);
698
699 /*
700 * While the busy_wait_ms() works with the maximum possible resolution,
701 * the k_timer api is limited by the system tick abstraction. As result
702 * the value obtained through k_timer_remaining_get() could be larger
703 * than actual remaining time with maximum error equal to one tick.
704 */
705 zassert_true(rem_ms <= (DURATION / 2) + k_ticks_to_ms_floor64(1),
706 NULL);
707
708 /* Half the value of DURATION in ticks may not be the value of
709 * half DURATION in ticks, when DURATION/2 is not an integer
710 * multiple of ticks, so target_rem_ticks is used rather than
711 * dur_ticks/2. Also set a threshold based on expected clock
712 * skew.
713 */
714 delta_ticks = (int32_t)(rem_ticks - target_rem_ticks);
715 slew_ticks = BUSY_SLEW_THRESHOLD_TICKS(DURATION * USEC_PER_MSEC / 2U);
716 zassert_true(abs(delta_ticks) <= MAX(slew_ticks, 1U),
717 "tick/busy slew %d larger than test threshold %u",
718 delta_ticks, slew_ticks);
719
720 /* Note +1 tick precision: even though we're calculating in
721 * ticks, we're waiting in k_busy_wait(), not for a timer
722 * interrupt, so it's possible for that to take 1 tick longer
723 * than expected on systems where the requested microsecond
724 * delay cannot be exactly represented as an integer number of
725 * ticks.
726 * As above, use higher tolerance on platforms where the clock used
727 * by the kernel timer and the one used for busy-waiting may be skewed.
728 */
729 zassert_true(((int64_t)exp_ticks - (int64_t)now)
730 <= (dur_ticks / 2) + 1 + slew_ticks, NULL);
731 }
732
ZTEST_USER(timer_api,test_timeout_abs)733 ZTEST_USER(timer_api, test_timeout_abs)
734 {
735 #ifdef CONFIG_TIMEOUT_64BIT
736 const uint64_t exp_ms = 10000000;
737 uint64_t rem_ticks;
738 uint64_t exp_ticks = k_ms_to_ticks_ceil64(exp_ms);
739 k_timeout_t t = K_TIMEOUT_ABS_TICKS(exp_ticks), t2;
740 uint64_t t0, t1;
741
742 /* Check the other generator macros to make sure they produce
743 * the same (whiteboxed) converted values
744 */
745 t2 = K_TIMEOUT_ABS_MS(exp_ms);
746 zassert_true(t2.ticks == t.ticks);
747
748 t2 = K_TIMEOUT_ABS_US(1000 * exp_ms);
749 zassert_true(t2.ticks == t.ticks);
750
751 t2 = K_TIMEOUT_ABS_NS(1000 * 1000 * exp_ms);
752 zassert_true(t2.ticks == t.ticks);
753
754 t2 = K_TIMEOUT_ABS_CYC(k_ms_to_cyc_ceil64(exp_ms));
755 zassert_true(t2.ticks == t.ticks);
756
757 /* Now set the timeout and make sure the expiration time is
758 * correct vs. current time. Tick units and tick alignment
759 * makes this math exact, no slop is needed. Note that time
760 * is advancing always, so we add a retry condition to be sure
761 * that a tick advance did not happen between our reads of
762 * "now" and "expires".
763 */
764 init_timer_data();
765 k_timer_start(&remain_timer, t, K_FOREVER);
766
767 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
768 k_usleep(1);
769 }
770
771 do {
772 t0 = k_uptime_ticks();
773 rem_ticks = k_timer_remaining_ticks(&remain_timer);
774 t1 = k_uptime_ticks();
775 } while (t0 != t1);
776
777 zassert_true(t0 + rem_ticks == exp_ticks,
778 "Wrong remaining: now %lld rem %lld expires %lld (%d)",
779 (uint64_t)t0, (uint64_t)rem_ticks, (uint64_t)exp_ticks,
780 t0+rem_ticks-exp_ticks);
781
782 k_timer_stop(&remain_timer);
783 #endif
784 }
785
ZTEST_USER(timer_api,test_sleep_abs)786 ZTEST_USER(timer_api, test_sleep_abs)
787 {
788 if (!IS_ENABLED(CONFIG_MULTITHREADING)) {
789 /* k_sleep is not supported when multithreading is off. */
790 return;
791 }
792
793 const int sleep_ticks = 50;
794 int64_t start, end;
795
796 k_usleep(1); /* tick align */
797
798 start = k_uptime_ticks();
799 k_sleep(K_TIMEOUT_ABS_TICKS(start + sleep_ticks));
800 end = k_uptime_ticks();
801
802 /* Systems with very high tick rates and/or slow idle resume
803 * (I've seen this on intel_adsp) can occasionally take more
804 * than a tick to return from k_sleep(). Set a 100us real
805 * time slop or more depending on the time to resume
806 */
807 k_ticks_t late = end - (start + sleep_ticks);
808 int slop = MAX(2, k_us_to_ticks_ceil32(250));
809
810 zassert_true(late >= 0 && late <= slop,
811 "expected wakeup at %lld, got %lld (late %lld)",
812 start + sleep_ticks, end, late);
813
814 /* Let's test that an absolute delay awakes at the correct time
815 * even if the system did not get some ticks announcements
816 */
817 int tickless_wait = 5;
818
819 start = end;
820 k_busy_wait(k_ticks_to_us_ceil32(tickless_wait));
821 /* We expect to not have got <tickless_wait> tick announcements,
822 * as there is currently nothing scheduled
823 */
824 k_sleep(K_TIMEOUT_ABS_TICKS(start + sleep_ticks));
825 end = k_uptime_ticks();
826 late = end - (start + sleep_ticks);
827
828 zassert_true(late >= 0 && late <= slop,
829 "expected wakeup at %lld, got %lld (late %lld)",
830 start + sleep_ticks, end, late);
831
832 }
833
timer_init(struct k_timer * timer,k_timer_expiry_t expiry_fn,k_timer_stop_t stop_fn)834 static void timer_init(struct k_timer *timer, k_timer_expiry_t expiry_fn,
835 k_timer_stop_t stop_fn)
836 {
837 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
838 k_object_access_grant(timer, k_current_get());
839 }
840
841 k_timer_init(timer, expiry_fn, stop_fn);
842 }
843
setup_timer_api(void)844 void *setup_timer_api(void)
845 {
846 timer_init(&duration_timer, duration_expire, duration_stop);
847 timer_init(&period0_timer, period0_expire, NULL);
848 timer_init(&expire_timer, NULL, duration_stop);
849 timer_init(&sync_timer, NULL, NULL);
850 timer_init(&periodicity_timer, NULL, NULL);
851 timer_init(&status_timer, status_expire, status_stop);
852 timer_init(&status_anytime_timer, NULL, NULL);
853 timer_init(&status_sync_timer, duration_expire, duration_stop);
854 timer_init(&remain_timer, duration_expire, duration_stop);
855
856 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
857 k_thread_access_grant(k_current_get(), &ktimer, &timer0, &timer1,
858 &timer2, &timer3, &timer4);
859 }
860
861 return NULL;
862 }
863
864 ZTEST_SUITE(timer_api, NULL, setup_timer_api, NULL, NULL, NULL);
865