1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @file
9 * @brief Use fifo API's in different scenarios
10 *
11 * This module tests following three basic scenarios:
12 *
13 * Scenario #1
14 * Test Thread enters items into a fifo, starts the Child Thread
15 * and waits for a semaphore. Child thread extracts all items from
16 * the fifo and enters some items back into the fifo. Child Thread
17 * gives the semaphore for Test Thread to continue. Once the control
18 * is returned back to Test Thread, it extracts all items from the fifo.
19 *
20 * Scenario #2
21 * Test Thread enters an item into fifo2, starts a Child Thread and
22 * extract an item from fifo1 once the item is there. The Child Thread
23 * will extract an item from fifo2 once the item is there and and enter
24 * an item to fifo1. The flow of control goes from Test Thread to
25 * Child Thread and so forth.
26 *
27 * Scenario #3
28 * Tests the ISR interfaces. Test thread puts items into fifo2 and gives
29 * control to the Child thread. Child thread gets items from fifo2 and then
30 * puts items into fifo1. Child thread gives back control to the Test thread
31 * and Test thread gets the items from fifo1.
32 * All the Push and Pop operations happen in ISR Context.
33 */
34
35 #include <zephyr/ztest.h>
36 #include <zephyr/irq_offload.h>
37
38 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
39 #define LIST_LEN 4
40
41 struct fdata_t {
42 sys_snode_t snode;
43 uint32_t data;
44 };
45
46 static K_FIFO_DEFINE(fifo1);
47 static K_FIFO_DEFINE(fifo2);
48
49 /* Data to put into FIFO */
50 static struct fdata_t data1[LIST_LEN];
51 static struct fdata_t data2[LIST_LEN];
52 static struct fdata_t data_isr[LIST_LEN];
53
54 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
55 static struct k_thread tdata;
56 static struct k_sem end_sema;
57
58 /*entry of contexts*/
tIsr_entry_put(const void * p)59 static void tIsr_entry_put(const void *p)
60 {
61 uint32_t i;
62
63 /* Put items into fifo */
64 for (i = 0U; i < LIST_LEN; i++) {
65 k_fifo_put((struct k_fifo *)p, (void *)&data_isr[i]);
66 }
67 zassert_false(k_fifo_is_empty((struct k_fifo *)p));
68 }
69
tIsr_entry_get(const void * p)70 static void tIsr_entry_get(const void *p)
71 {
72 void *rx_data;
73 uint32_t i;
74
75 /* Get items from fifo */
76 for (i = 0U; i < LIST_LEN; i++) {
77 rx_data = k_fifo_get((struct k_fifo *)p, K_NO_WAIT);
78 zassert_equal(rx_data, (void *)&data_isr[i]);
79 }
80 zassert_true(k_fifo_is_empty((struct k_fifo *)p));
81 }
82
thread_entry_fn_single(void * p1,void * p2,void * p3)83 static void thread_entry_fn_single(void *p1, void *p2, void *p3)
84 {
85 void *rx_data;
86 uint32_t i;
87
88 /* Get items from fifo */
89 for (i = 0U; i < LIST_LEN; i++) {
90 rx_data = k_fifo_get((struct k_fifo *)p1, K_NO_WAIT);
91 zassert_equal(rx_data, (void *)&data1[i]);
92 }
93
94 /* Put items into fifo */
95 for (i = 0U; i < LIST_LEN; i++) {
96 k_fifo_put((struct k_fifo *)p1, (void *)&data2[i]);
97 }
98
99 /* Give control back to Test thread */
100 k_sem_give(&end_sema);
101 }
102
thread_entry_fn_dual(void * p1,void * p2,void * p3)103 static void thread_entry_fn_dual(void *p1, void *p2, void *p3)
104 {
105 void *rx_data;
106 uint32_t i;
107
108 for (i = 0U; i < LIST_LEN; i++) {
109 /* Get items from fifo2 */
110 rx_data = k_fifo_get((struct k_fifo *)p2, K_FOREVER);
111 zassert_equal(rx_data, (void *)&data2[i]);
112
113 /* Put items into fifo1 */
114 k_fifo_put((struct k_fifo *)p1, (void *)&data1[i]);
115 }
116 }
117
thread_entry_fn_isr(void * p1,void * p2,void * p3)118 static void thread_entry_fn_isr(void *p1, void *p2, void *p3)
119 {
120 /* Get items from fifo2 */
121 irq_offload(tIsr_entry_get, (const void *)p2);
122
123 /* Put items into fifo1 */
124 irq_offload(tIsr_entry_put, (const void *)p1);
125
126 /* Give control back to Test thread */
127 k_sem_give(&end_sema);
128 }
129
130 /**
131 * @addtogroup kernel_fifo_tests
132 * @{
133 */
134
135 /**
136 * @brief Tests single fifo get and put operation in thread context
137 * @details Test Thread enters items into a fifo, starts the Child Thread
138 * and waits for a semaphore. Child thread extracts all items from
139 * the fifo and enters some items back into the fifo. Child Thread
140 * gives the semaphore for Test Thread to continue. Once the control
141 * is returned back to Test Thread, it extracts all items from the fifo.
142 * @see k_fifo_get(), k_fifo_is_empty(), k_fifo_put(), #K_FIFO_DEFINE(x)
143 */
ZTEST(fifo_usage,test_single_fifo_play)144 ZTEST(fifo_usage, test_single_fifo_play)
145 {
146 void *rx_data;
147 uint32_t i;
148
149 /* Init kernel objects */
150 k_sem_init(&end_sema, 0, 1);
151
152 /* Put items into fifo */
153 for (i = 0U; i < LIST_LEN; i++) {
154 k_fifo_put(&fifo1, (void *)&data1[i]);
155 }
156
157 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
158 thread_entry_fn_single, &fifo1, NULL, NULL,
159 K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT);
160
161 /* Let the child thread run */
162 k_sem_take(&end_sema, K_FOREVER);
163
164 /* Get items from fifo */
165 for (i = 0U; i < LIST_LEN; i++) {
166 rx_data = k_fifo_get(&fifo1, K_NO_WAIT);
167 zassert_equal(rx_data, (void *)&data2[i]);
168 }
169
170 /* Clear the spawn thread to avoid side effect */
171 k_thread_abort(tid);
172 }
173
174 /**
175 * @brief Tests dual fifo get and put operation in thread context
176 * @details test Thread enters an item into fifo2, starts a Child Thread and
177 * extract an item from fifo1 once the item is there. The Child Thread
178 * will extract an item from fifo2 once the item is there and and enter
179 * an item to fifo1. The flow of control goes from Test Thread to
180 * Child Thread and so forth.
181 * @see k_fifo_get(), k_fifo_is_empty(), k_fifo_put(), #K_FIFO_DEFINE(x)
182 */
ZTEST(fifo_usage,test_dual_fifo_play)183 ZTEST(fifo_usage, test_dual_fifo_play)
184 {
185 void *rx_data;
186 uint32_t i;
187
188 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
189 thread_entry_fn_dual, &fifo1, &fifo2, NULL,
190 K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT);
191
192 for (i = 0U; i < LIST_LEN; i++) {
193 /* Put item into fifo */
194 k_fifo_put(&fifo2, (void *)&data2[i]);
195
196 /* Get item from fifo */
197 rx_data = k_fifo_get(&fifo1, K_FOREVER);
198 zassert_equal(rx_data, (void *)&data1[i]);
199 }
200
201 /* Clear the spawn thread to avoid side effect */
202 k_thread_abort(tid);
203
204 }
205
206 /**
207 * @brief Tests fifo put and get operation in interrupt context
208 * @details Tests the ISR interfaces. Test thread puts items into fifo2
209 * and gives control to the Child thread. Child thread gets items from
210 * fifo2 and then puts items into fifo1. Child thread gives back control
211 * to the Test thread and Test thread gets the items from fifo1.
212 * All the Push and Pop operations happen in ISR Context.
213 * @see k_fifo_get(), k_fifo_is_empty(), k_fifo_put(), #K_FIFO_DEFINE(x)
214 */
ZTEST(fifo_usage,test_isr_fifo_play)215 ZTEST(fifo_usage, test_isr_fifo_play)
216 {
217 /* Init kernel objects */
218 k_sem_init(&end_sema, 0, 1);
219
220 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
221 thread_entry_fn_isr, &fifo1, &fifo2, NULL,
222 K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT);
223
224
225 /* Put item into fifo */
226 irq_offload(tIsr_entry_put, (const void *)&fifo2);
227
228 /* Let the child thread run */
229 k_sem_take(&end_sema, K_FOREVER);
230
231 /* Get item from fifo */
232 irq_offload(tIsr_entry_get, (const void *)&fifo1);
233
234 /* Clear the spawn thread to avoid side effect */
235 k_thread_abort(tid);
236 }
237
238 /**
239 * @}
240 */
241
242 ZTEST_SUITE(fifo_usage, NULL, NULL,
243 ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
244