| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/ztest.h> |
| |
| #define ALIGN_MS_BOUNDARY \ |
| do { \ |
| uint32_t t = k_uptime_get_32(); \ |
| while (t == k_uptime_get_32()) \ |
| Z_SPIN_DELAY(50); \ |
| } while (0) |
| |
| /** @cond INTERNAL_HIDDEN */ |
| struct timer_data { |
| int duration_count; |
| int stop_count; |
| }; |
| static void duration_expire(struct k_timer *timer); |
| static void stop_expire(struct k_timer *timer); |
| |
| /* TESTPOINT: init timer via K_TIMER_DEFINE */ |
| K_TIMER_DEFINE(ktimer, duration_expire, stop_expire); |
| |
| static ZTEST_BMEM struct timer_data tdata; |
| /** @endcond */ |
| |
| #define DURATION 100 |
| #define LESS_DURATION 70 |
| |
| /** |
| * @defgroup kernel_clock_tests Clock Operations |
| * @ingroup all_tests |
| * @{ |
| * @} |
| * |
| * @addtogroup kernel_clock_tests |
| * @{ |
| */ |
| |
| /** |
| * @brief Verify the uptime clock advances monotonically and reports deltas. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves the system uptime clock is a forward-progressing time source |
| * usable from user mode: both the 64-bit and lower-32-bit millisecond uptime |
| * readings increase as wall time elapses and the 32-bit reading observes a |
| * millisecond boundary crossing. |
| * |
| * Test steps: |
| * - Spin until k_uptime_get() advances by at least 5 ms. |
| * - Spin until k_uptime_get_32() advances by at least 5 ms. |
| * - Sample the 32-bit uptime, align to a millisecond boundary, and confirm it grew. |
| * |
| * Expected result: |
| * - The millisecond uptime readings increase over time. |
| * |
| * @see k_uptime_get(), k_uptime_get_32() |
| */ |
| ZTEST_USER(clock, test_clock_uptime) |
| { |
| uint64_t t64, t32; |
| |
| /**TESTPOINT: uptime elapse*/ |
| t64 = k_uptime_get(); |
| while (k_uptime_get() < (t64 + 5)) { |
| Z_SPIN_DELAY(50); |
| } |
| |
| /**TESTPOINT: uptime elapse lower 32-bit*/ |
| t32 = k_uptime_get_32(); |
| while (k_uptime_get_32() < (t32 + 5)) { |
| Z_SPIN_DELAY(50); |
| } |
| |
| /**TESTPOINT: uptime straddled ms boundary*/ |
| t32 = k_uptime_get_32(); |
| ALIGN_MS_BOUNDARY; |
| zassert_true(k_uptime_get_32() > t32); |
| } |
| |
| /** |
| * @brief Verify the system uptime is reported in system ticks. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves k_uptime_ticks() is a forward-progressing reading of the |
| * system uptime in ticks, usable from user mode. |
| * |
| * Test steps: |
| * - Sample k_uptime_ticks() and spin until it advances. |
| * |
| * Expected result: |
| * - The tick reading increases as wall time elapses. |
| * |
| * @see k_uptime_ticks() |
| */ |
| ZTEST_USER(clock, test_clock_uptime_ticks) |
| { |
| int64_t ticks = k_uptime_ticks(); |
| |
| /**TESTPOINT: uptime in system ticks advances*/ |
| while (k_uptime_ticks() <= ticks) { |
| Z_SPIN_DELAY(50); |
| } |
| } |
| |
| /** |
| * @brief Verify the system uptime is reported in whole seconds. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves k_uptime_seconds() reports the uptime in seconds |
| * consistently with the millisecond uptime clock: the value equals the |
| * floor of the millisecond reading converted to seconds. |
| * |
| * Test steps: |
| * - Sample k_uptime_seconds() between two k_uptime_get() readings. |
| * - Check the seconds value against the floor of both millisecond readings. |
| * |
| * Expected result: |
| * - The seconds reading is bounded by the floors of the surrounding |
| * millisecond readings. |
| * |
| * @see k_uptime_seconds() |
| */ |
| ZTEST_USER(clock, test_clock_uptime_seconds) |
| { |
| /**TESTPOINT: uptime in seconds is consistent with the millisecond reading*/ |
| uint64_t ms_before = k_uptime_get(); |
| uint32_t secs = k_uptime_seconds(); |
| uint64_t ms_after = k_uptime_get(); |
| |
| zassert_true(secs >= (ms_before / MSEC_PER_SEC), |
| "uptime seconds %u below floor of %llu ms", secs, ms_before); |
| zassert_true(secs <= (ms_after / MSEC_PER_SEC), |
| "uptime seconds %u above floor of %llu ms", secs, ms_after); |
| } |
| |
| /** |
| * @brief Verify elapsed time reporting relative to a reference. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves k_uptime_delta() measures the time elapsed since a |
| * caller-held reference time and updates the reference for the next |
| * measurement. |
| * |
| * Test steps: |
| * - Seed a delta reference, then spin until k_uptime_delta() returns a |
| * non-zero elapsed time. |
| * |
| * Expected result: |
| * - k_uptime_delta() reports a non-zero interval once time has elapsed. |
| * |
| * @see k_uptime_delta() |
| */ |
| ZTEST_USER(clock, test_clock_uptime_delta) |
| { |
| int64_t d64 = 0; |
| |
| /**TESTPOINT: uptime delta*/ |
| d64 = k_uptime_delta(&d64); |
| while (k_uptime_delta(&d64) == 0) { |
| Z_SPIN_DELAY(50); |
| } |
| } |
| |
| /** |
| * @brief Verify the 32-bit cycle counter advances consistently with uptime. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves that the architecture's 32-bit hardware cycle counter |
| * (k_cycle_get_32()) is a monotonically increasing time source whose rate is |
| * consistent with the tick-derived uptime clock (k_uptime_get_32()): the number |
| * of cycles elapsed over one observed millisecond of uptime corresponds to at |
| * least one millisecond worth of cycles and at least one millisecond when |
| * converted to nanoseconds, cross-validating the cycle counter against uptime. |
| * |
| * Test steps: |
| * - Align to a millisecond boundary and spin until the cycle counter advances, |
| * guarding against counter wrap-around. |
| * - Sample the cycle counter, align to a millisecond boundary, and spin until |
| * the 32-bit uptime advances by one millisecond. |
| * - Compute the cycle delta over that interval (skipping if the counter wrapped). |
| * |
| * Expected result: |
| * - The cycle delta exceeds one millisecond of cycles and, converted via |
| * k_cyc_to_ns_floor64(), exceeds one millisecond in nanoseconds. |
| * |
| * @see k_cycle_get_32(), k_uptime_get_32() |
| */ |
| |
| ZTEST(clock, test_clock_cycle_32) |
| { |
| uint32_t c32, c0, c1, t32; |
| |
| /**TESTPOINT: cycle elapse*/ |
| ALIGN_MS_BOUNDARY; |
| c32 = k_cycle_get_32(); |
| /*break if cycle counter wrap around*/ |
| while (k_cycle_get_32() > c32 && |
| k_cycle_get_32() < (c32 + k_ticks_to_cyc_floor32(1))) { |
| Z_SPIN_DELAY(50); |
| } |
| |
| /**TESTPOINT: cycle/uptime cross check*/ |
| c0 = k_cycle_get_32(); |
| ALIGN_MS_BOUNDARY; |
| t32 = k_uptime_get_32(); |
| while (t32 == k_uptime_get_32()) { |
| Z_SPIN_DELAY(50); |
| } |
| |
| c1 = k_uptime_get_32(); |
| /*avoid cycle counter wrap around*/ |
| if (c1 > c0) { |
| /* delta cycle should be greater than 1 milli-second*/ |
| zassert_true((c1 - c0) > (sys_clock_hw_cycles_per_sec() / MSEC_PER_SEC)); |
| /* delta NS should be greater than 1 milli-second */ |
| zassert_true((uint32_t)k_cyc_to_ns_floor64(c1 - c0) > |
| (NSEC_PER_SEC / MSEC_PER_SEC)); |
| } |
| } |
| |
| /** |
| * @brief Verify the 64-bit cycle counter tracks the 32-bit counter over an interval. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves that, on platforms providing a 64-bit cycle counter, the |
| * 64-bit and 32-bit cycle counters measure the same elapsed time over a short |
| * sleep: the 64-bit delta is at least as large as the 32-bit delta (it does not |
| * lose resolution) yet remains below twice the 32-bit delta (it does not run at |
| * a different rate). The test skips on platforms without a 64-bit cycle counter. |
| * |
| * Test steps: |
| * - Skip unless CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER is enabled. |
| * - Sample both the 64-bit and 32-bit cycle counters, sleep 1 ms, then sample again. |
| * - Compute the 32-bit and 64-bit deltas across the sleep. |
| * |
| * Expected result: |
| * - The 64-bit delta is >= the 32-bit delta and < twice the 32-bit delta. |
| * |
| * @see k_cycle_get_64() |
| */ |
| ZTEST(clock, test_clock_cycle_64) |
| { |
| uint32_t d32; |
| uint64_t d64; |
| uint32_t t32[2]; |
| uint64_t t64[2]; |
| |
| if (!IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) { |
| ztest_test_skip(); |
| } |
| |
| t64[0] = k_cycle_get_64(); |
| t32[0] = k_cycle_get_32(); |
| |
| k_msleep(1); |
| |
| t32[1] = k_cycle_get_32(); |
| t64[1] = k_cycle_get_64(); |
| |
| d32 = MIN(t32[1] - t32[0], t32[0] - t32[1]); |
| d64 = MIN(t64[1] - t64[0], t64[1] - t64[0]); |
| |
| zassert_true(d64 >= d32, |
| "k_cycle_get() (64-bit): d64: %" PRIu64 " < d32: %u", d64, d32); |
| |
| zassert_true(d64 < (d32 << 1), |
| "k_cycle_get() (64-bit): d64: %" PRIu64 " >= 2 * d32: %u", |
| d64, (d32 << 1)); |
| } |
| |
| /* |
| *help function |
| */ |
| static void duration_expire(struct k_timer *timer) |
| { |
| tdata.duration_count++; |
| } |
| |
| static void stop_expire(struct k_timer *timer) |
| { |
| tdata.stop_count++; |
| } |
| |
| static void init_data_count(void) |
| { |
| tdata.duration_count = 0; |
| tdata.stop_count = 0; |
| } |
| |
| /** |
| * @brief Verify a kernel timer expires only after its millisecond duration elapses. |
| * |
| * @ingroup kernel_clock_tests |
| * |
| * @details |
| * Passing proves that k_timer_start() honors a millisecond expiry duration with |
| * correct timing semantics: the timer's expiry callback does not fire while less |
| * than the configured duration has elapsed, and fires exactly once once the full |
| * duration is exceeded, while the stop callback is not invoked on normal expiry. |
| * |
| * Test steps: |
| * - Start the timer for DURATION ms one-shot and busy-wait LESS_DURATION ms; |
| * confirm neither the expiry nor stop counter has incremented. |
| * - Restart the timer, align to a tick, busy-wait just over DURATION ms, and |
| * confirm the expiry counter is exactly 1 and the stop counter is 0. |
| * - Stop the timer to clean up. |
| * |
| * Expected result: |
| * - No expiry before the duration elapses; exactly one expiry afterward and no |
| * stop-callback invocation. |
| * |
| * @see k_timer_start(), k_timer_stop(), k_busy_wait() |
| * |
| */ |
| |
| ZTEST(clock, test_ms_time_duration) |
| { |
| init_data_count(); |
| k_timer_start(&ktimer, K_MSEC(DURATION), K_NO_WAIT); |
| |
| /** TESTPOINT: waiting time less than duration and check the count*/ |
| k_busy_wait(LESS_DURATION * 1000); |
| zassert_true(tdata.duration_count == 0); |
| zassert_true(tdata.stop_count == 0); |
| |
| /** TESTPOINT: proving duration in millisecond */ |
| init_data_count(); |
| k_timer_start(&ktimer, K_MSEC(100), K_MSEC(50)); |
| |
| /** TESTPOINT: waiting time more than duration and check the count */ |
| k_usleep(1); /* align to tick */ |
| k_busy_wait((DURATION + 1) * 1000); |
| zassert_true(tdata.duration_count == 1, "duration %u not 1", |
| tdata.duration_count); |
| zassert_true(tdata.stop_count == 0, |
| "stop %u not 0", tdata.stop_count); |
| |
| /** cleanup environment */ |
| k_timer_stop(&ktimer); |
| } |
| |
| /** |
| * @} |
| */ |
| |
| extern void *common_setup(void); |
| ZTEST_SUITE(clock, NULL, common_setup, NULL, NULL, NULL); |