| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <ztest.h> |
| |
| #if defined(CONFIG_ARCH_POSIX) |
| #define ALIGN_MS_BOUNDARY \ |
| do { \ |
| uint32_t t = k_uptime_get_32(); \ |
| while (t == k_uptime_get_32()) \ |
| k_busy_wait(50); \ |
| } while (0) |
| #else |
| #define ALIGN_MS_BOUNDARY \ |
| do { \ |
| uint32_t t = k_uptime_get_32(); \ |
| while (t == k_uptime_get_32()) \ |
| ; \ |
| } while (0) |
| #endif |
| |
| 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; |
| |
| #define DURATION 100 |
| #define LESS_DURATION 80 |
| |
| /** |
| * @addtogroup kernel_common_tests |
| * @{ |
| */ |
| |
| /** |
| * @brief Test clock uptime APIs functionality |
| * |
| * @see k_uptime_get(), k_uptime_get_32(), k_uptime_delta() |
| */ |
| void test_clock_uptime(void) |
| { |
| uint64_t t64, t32; |
| int64_t d64 = 0; |
| |
| /**TESTPOINT: uptime elapse*/ |
| t64 = k_uptime_get(); |
| while (k_uptime_get() < (t64 + 5)) { |
| #if defined(CONFIG_ARCH_POSIX) |
| k_busy_wait(50); |
| #endif |
| } |
| |
| /**TESTPOINT: uptime elapse lower 32-bit*/ |
| t32 = k_uptime_get_32(); |
| while (k_uptime_get_32() < (t32 + 5)) { |
| #if defined(CONFIG_ARCH_POSIX) |
| k_busy_wait(50); |
| #endif |
| } |
| |
| /**TESTPOINT: uptime straddled ms boundary*/ |
| t32 = k_uptime_get_32(); |
| ALIGN_MS_BOUNDARY; |
| zassert_true(k_uptime_get_32() > t32, NULL); |
| |
| /**TESTPOINT: uptime delta*/ |
| d64 = k_uptime_delta(&d64); |
| while (k_uptime_delta(&d64) == 0) { |
| #if defined(CONFIG_ARCH_POSIX) |
| k_busy_wait(50); |
| #endif |
| } |
| } |
| |
| /** |
| * @brief Test 32-bit clock cycle functionality |
| * |
| * @details |
| * Test Objective: |
| * - The kernel architecture provide a 32bit monotonically increasing |
| * cycle counter |
| * - This routine tests the k_cycle_get_32() and k_uptime_get_32() |
| * k_cycle_get_32() get cycles by accessing hardware clock. |
| * k_uptime_get_32() return cycles by transforming ticks into cycles. |
| * |
| * Testing techniques |
| * - Functional and black box testing |
| * |
| * Prerequisite Condition: |
| * - N/A |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Expected Test Result: |
| * - The timer increases monotonically |
| * |
| * Pass/Fail criteria: |
| * - Success if cycles increase monotonically, failure otherwise. |
| * |
| * Test Procedure: |
| * -# At milli-second boundary, get cycles repeatedly by k_cycle_get_32() |
| * till cycles increased |
| * -# At milli-second boundary, get cycles repeatedly by k_uptime_get_32() |
| * till cycles increased |
| * -# Cross check cycles gotten by k_cycle_get_32() and k_uptime_get_32(), |
| * the delta cycle should be greater than 1 milli-second. |
| * |
| * Assumptions and Constraints |
| * - N/A |
| * |
| * @see k_cycle_get_32(), k_uptime_get_32() |
| */ |
| |
| void test_clock_cycle_32(void) |
| { |
| 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))) { |
| #if defined(CONFIG_ARCH_POSIX) |
| k_busy_wait(50); |
| #endif |
| } |
| |
| /**TESTPOINT: cycle/uptime cross check*/ |
| c0 = k_cycle_get_32(); |
| ALIGN_MS_BOUNDARY; |
| t32 = k_uptime_get_32(); |
| while (t32 == k_uptime_get_32()) { |
| #if defined(CONFIG_ARCH_POSIX) |
| k_busy_wait(50); |
| #endif |
| } |
| |
| 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), |
| NULL); |
| /* 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), NULL); |
| } |
| } |
| |
| /** |
| * @brief Test 64-bit clock cycle functionality |
| */ |
| void test_clock_cycle_64(void) |
| { |
| 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 Test millisecond time duration |
| * |
| * @details initialize a timer, then providing time duration in |
| * millisecond, and check the duration time whether correct. |
| * |
| * @see k_timer_init(), k_timer_start(), k_timer_stop(), |
| * k_busy_wait() |
| * |
| * |
| */ |
| |
| void test_ms_time_duration(void) |
| { |
| 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, NULL); |
| zassert_true(tdata.stop_count == 0, NULL); |
| |
| /** 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); |
| } |
| /** |
| * @} |
| */ |