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