1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 
9 #define ALIGN_MS_BOUNDARY		       \
10 	do {				       \
11 		uint32_t t = k_uptime_get_32();   \
12 		while (t == k_uptime_get_32()) \
13 			Z_SPIN_DELAY(50);      \
14 	} while (0)
15 
16 struct timer_data {
17 	int duration_count;
18 	int stop_count;
19 };
20 static void duration_expire(struct k_timer *timer);
21 static void stop_expire(struct k_timer *timer);
22 
23 /** TESTPOINT: init timer via K_TIMER_DEFINE */
24 K_TIMER_DEFINE(ktimer, duration_expire, stop_expire);
25 
26 static ZTEST_BMEM struct timer_data tdata;
27 
28 #define DURATION 100
29 #define LESS_DURATION 70
30 
31 /**
32  * @addtogroup kernel_common_tests
33  * @{
34  */
35 
36 /**
37  * @brief Test clock uptime APIs functionality
38  *
39  * @see k_uptime_get(), k_uptime_get_32(), k_uptime_delta()
40  */
ZTEST_USER(clock,test_clock_uptime)41 ZTEST_USER(clock, test_clock_uptime)
42 {
43 	uint64_t t64, t32;
44 	int64_t d64 = 0;
45 
46 	/**TESTPOINT: uptime elapse*/
47 	t64 = k_uptime_get();
48 	while (k_uptime_get() < (t64 + 5)) {
49 		Z_SPIN_DELAY(50);
50 	}
51 
52 	/**TESTPOINT: uptime elapse lower 32-bit*/
53 	t32 = k_uptime_get_32();
54 	while (k_uptime_get_32() < (t32 + 5)) {
55 		Z_SPIN_DELAY(50);
56 	}
57 
58 	/**TESTPOINT: uptime straddled ms boundary*/
59 	t32 = k_uptime_get_32();
60 	ALIGN_MS_BOUNDARY;
61 	zassert_true(k_uptime_get_32() > t32);
62 
63 	/**TESTPOINT: uptime delta*/
64 	d64 = k_uptime_delta(&d64);
65 	while (k_uptime_delta(&d64) == 0) {
66 		Z_SPIN_DELAY(50);
67 	}
68 }
69 
70 /**
71  * @brief Test 32-bit clock cycle functionality
72  *
73  * @details
74  * Test Objective:
75  * - The kernel architecture provide a 32bit monotonically increasing
76  *   cycle counter
77  * - This routine tests the k_cycle_get_32() and k_uptime_get_32()
78  *   k_cycle_get_32() get cycles by accessing hardware clock.
79  *   k_uptime_get_32() return cycles by transforming ticks into cycles.
80  *
81  * Testing techniques
82  * - Functional and black box testing
83  *
84  * Prerequisite Condition:
85  * - N/A
86  *
87  * Input Specifications:
88  * - N/A
89  *
90  * Expected Test Result:
91  * - The timer increases monotonically
92  *
93  * Pass/Fail criteria:
94  * - Success if cycles increase monotonically, failure otherwise.
95  *
96  * Test Procedure:
97  * -# At milli-second boundary, get cycles repeatedly by k_cycle_get_32()
98  *  till cycles increased
99  * -# At milli-second boundary, get cycles repeatedly by k_uptime_get_32()
100  *  till cycles increased
101  * -# Cross check cycles gotten by k_cycle_get_32() and k_uptime_get_32(),
102  *  the delta cycle should be greater than 1 milli-second.
103  *
104  * Assumptions and Constraints
105  * - N/A
106  *
107  * @see k_cycle_get_32(), k_uptime_get_32()
108  */
109 
ZTEST(clock,test_clock_cycle_32)110 ZTEST(clock, test_clock_cycle_32)
111 {
112 	uint32_t c32, c0, c1, t32;
113 
114 	/**TESTPOINT: cycle elapse*/
115 	ALIGN_MS_BOUNDARY;
116 	c32 = k_cycle_get_32();
117 	/*break if cycle counter wrap around*/
118 	while (k_cycle_get_32() > c32 &&
119 	       k_cycle_get_32() < (c32 + k_ticks_to_cyc_floor32(1))) {
120 		Z_SPIN_DELAY(50);
121 	}
122 
123 	/**TESTPOINT: cycle/uptime cross check*/
124 	c0 = k_cycle_get_32();
125 	ALIGN_MS_BOUNDARY;
126 	t32 = k_uptime_get_32();
127 	while (t32 == k_uptime_get_32()) {
128 		Z_SPIN_DELAY(50);
129 	}
130 
131 	c1 = k_uptime_get_32();
132 	/*avoid cycle counter wrap around*/
133 	if (c1 > c0) {
134 		/* delta cycle should be greater than 1 milli-second*/
135 		zassert_true((c1 - c0) >
136 			     (sys_clock_hw_cycles_per_sec() / MSEC_PER_SEC),
137 			     NULL);
138 		/* delta NS should be greater than 1 milli-second */
139 		zassert_true((uint32_t)k_cyc_to_ns_floor64(c1 - c0) >
140 			     (NSEC_PER_SEC / MSEC_PER_SEC), NULL);
141 	}
142 }
143 
144 /**
145  * @brief Test 64-bit clock cycle functionality
146  */
ZTEST(clock,test_clock_cycle_64)147 ZTEST(clock, test_clock_cycle_64)
148 {
149 	uint32_t d32;
150 	uint64_t d64;
151 	uint32_t t32[2];
152 	uint64_t t64[2];
153 
154 	if (!IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) {
155 		ztest_test_skip();
156 	}
157 
158 	t64[0] = k_cycle_get_64();
159 	t32[0] = k_cycle_get_32();
160 
161 	k_msleep(1);
162 
163 	t32[1] = k_cycle_get_32();
164 	t64[1] = k_cycle_get_64();
165 
166 	d32 = MIN(t32[1] - t32[0], t32[0] - t32[1]);
167 	d64 = MIN(t64[1] - t64[0], t64[1] - t64[0]);
168 
169 	zassert_true(d64 >= d32,
170 		"k_cycle_get() (64-bit): d64: %" PRIu64 " < d32: %u", d64, d32);
171 
172 	zassert_true(d64 < (d32 << 1),
173 		"k_cycle_get() (64-bit): d64: %" PRIu64 " >= 2 * d32: %u",
174 		d64, (d32 << 1));
175 }
176 
177 /*
178  *help function
179  */
duration_expire(struct k_timer * timer)180 static void duration_expire(struct k_timer *timer)
181 {
182 	tdata.duration_count++;
183 }
184 
stop_expire(struct k_timer * timer)185 static void stop_expire(struct k_timer *timer)
186 {
187 	tdata.stop_count++;
188 }
189 
init_data_count(void)190 static void init_data_count(void)
191 {
192 	tdata.duration_count = 0;
193 	tdata.stop_count = 0;
194 }
195 
196 /**
197  * @brief Test millisecond time duration
198  *
199  * @details initialize a timer, then providing time duration in
200  * millisecond, and check the duration time whether correct.
201  *
202  * @see k_timer_init(), k_timer_start(), k_timer_stop(),
203  * k_busy_wait()
204  *
205  *
206  */
207 
ZTEST(clock,test_ms_time_duration)208 ZTEST(clock, test_ms_time_duration)
209 {
210 	init_data_count();
211 	k_timer_start(&ktimer, K_MSEC(DURATION), K_NO_WAIT);
212 
213 	/** TESTPOINT: waiting time less than duration and check the count*/
214 	k_busy_wait(LESS_DURATION * 1000);
215 	zassert_true(tdata.duration_count == 0);
216 	zassert_true(tdata.stop_count == 0);
217 
218 	/** TESTPOINT: proving duration in millisecond */
219 	init_data_count();
220 	k_timer_start(&ktimer, K_MSEC(100), K_MSEC(50));
221 
222 	/** TESTPOINT: waiting time more than duration and check the count */
223 	k_usleep(1);		/* align to tick */
224 	k_busy_wait((DURATION + 1) * 1000);
225 	zassert_true(tdata.duration_count == 1, "duration %u not 1",
226 		     tdata.duration_count);
227 	zassert_true(tdata.stop_count == 0,
228 		     "stop %u not 0", tdata.stop_count);
229 
230 	/** cleanup environment */
231 	k_timer_stop(&ktimer);
232 }
233 
234 extern void *common_setup(void);
235 ZTEST_SUITE(clock, NULL, common_setup, NULL, NULL, NULL);
236 
237 /**
238  * @}
239  */
240