1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/portability/cmsis_os2.h>
10 #include <zephyr/portability/cmsis_types.h>
11 
12 #include <zephyr/irq_offload.h>
13 #include <zephyr/kernel_structs.h>
14 
15 #define TIMEOUT_TICKS (100)
16 #define FLAG1         (0x00000020)
17 #define FLAG2         (0x00000004)
18 #define FLAG          (FLAG1 | FLAG2)
19 #define ISR_FLAG      0x50
20 #define STACKSZ       CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE
21 
22 osEventFlagsId_t evt_id;
23 
thread1(void * arg)24 static void thread1(void *arg)
25 {
26 	int flags = osEventFlagsSet((osEventFlagsId_t)arg, FLAG1);
27 
28 	zassert_equal(flags & FLAG1, FLAG1, "");
29 }
30 
thread2(void * arg)31 static void thread2(void *arg)
32 {
33 	int flags = osEventFlagsSet((osEventFlagsId_t)arg, FLAG2);
34 
35 	/* Please note that as soon as the last flag that a thread is waiting
36 	 * on is set, the control shifts to that thread and that thread may
37 	 * choose to clear the flags as part of its osEventFlagsWait operation.
38 	 * In this test case, the main thread is waiting for FLAG1 and FLAG2.
39 	 * FLAG1 gets set first and then FLAG2 gets set. As soon as FLAG2 gets
40 	 * set, control shifts to the waiting thread where osEventFlagsWait
41 	 * clears FLAG1 and FLAG2 internally. When this thread eventually gets
42 	 * scheduled we should hence check if FLAG2 is cleared.
43 	 */
44 	zassert_equal(flags & FLAG2, 0, "");
45 }
46 
47 static K_THREAD_STACK_DEFINE(test_stack1, STACKSZ);
48 static osThreadAttr_t thread1_attr = {
49 	.name = "Thread1",
50 	.stack_mem = &test_stack1,
51 	.stack_size = STACKSZ,
52 	.priority = osPriorityHigh,
53 };
54 
55 static K_THREAD_STACK_DEFINE(test_stack2, STACKSZ);
56 static osThreadAttr_t thread2_attr = {
57 	.name = "Thread2",
58 	.stack_mem = &test_stack2,
59 	.stack_size = STACKSZ,
60 	.priority = osPriorityHigh,
61 };
62 
63 static osEventFlagsAttr_t event_flags_attrs = {
64 	.name = "MyEvent",
65 	.attr_bits = 0,
66 	.cb_mem = NULL,
67 	.cb_size = 0,
68 };
69 
test_event_flags_no_wait_timeout(void)70 void test_event_flags_no_wait_timeout(void)
71 {
72 	osThreadId_t id1;
73 	uint32_t flags;
74 	const char *name;
75 	osEventFlagsId_t dummy_id = NULL;
76 
77 	evt_id = osEventFlagsNew(&event_flags_attrs);
78 	zassert_true(evt_id != NULL, "Failed creating event flags");
79 
80 	name = osEventFlagsGetName(dummy_id);
81 	zassert_true(name == NULL, "Invalid event Flags ID is unexpectedly working!");
82 
83 	name = osEventFlagsGetName(evt_id);
84 	zassert_str_equal(event_flags_attrs.name, name, "Error getting event_flags object name");
85 
86 	id1 = osThreadNew(thread1, evt_id, &thread1_attr);
87 	zassert_true(id1 != NULL, "Failed creating thread1");
88 
89 	/* Let id1 run to trigger FLAG1 */
90 	osDelay(2);
91 
92 	/* wait for FLAG1. It should return immediately as it is
93 	 * already triggered.
94 	 */
95 	flags = osEventFlagsWait(evt_id, FLAG1, osFlagsWaitAny | osFlagsNoClear, 0);
96 	zassert_equal(flags & FLAG1, FLAG1, "");
97 
98 	/* Since the flags are not cleared automatically in the previous step,
99 	 * we should be able to get the same flags upon query below.
100 	 */
101 	flags = osEventFlagsGet(evt_id);
102 	zassert_equal(flags & FLAG1, FLAG1, "");
103 
104 	flags = osEventFlagsGet(dummy_id);
105 	zassert_true(flags == 0U, "Invalid event Flags ID is unexpectedly working!");
106 	/* Clear the Flag explicitly */
107 	flags = osEventFlagsClear(evt_id, FLAG1);
108 	zassert_not_equal(flags, osFlagsErrorParameter, "Event clear failed");
109 
110 	/* wait for FLAG1. It should timeout here as the event
111 	 * though triggered, gets cleared in the previous step.
112 	 */
113 	flags = osEventFlagsWait(evt_id, FLAG1, osFlagsWaitAny, TIMEOUT_TICKS);
114 	zassert_equal(flags, osFlagsErrorTimeout, "EventFlagsWait failed");
115 }
116 
test_event_flags_signalled(void)117 void test_event_flags_signalled(void)
118 {
119 	osThreadId_t id1, id2;
120 	uint32_t flags;
121 
122 	id1 = osThreadNew(thread1, evt_id, &thread1_attr);
123 	zassert_true(id1 != NULL, "Failed creating thread1");
124 
125 	/* Let id1 run to trigger FLAG1 */
126 	osDelay(2);
127 
128 	id2 = osThreadNew(thread2, evt_id, &thread2_attr);
129 	zassert_true(id2 != NULL, "Failed creating thread2");
130 
131 	/* wait for multiple flags. The flags will be cleared automatically
132 	 * upon being set since "osFlagsNoClear" is not opted for.
133 	 */
134 	flags = osEventFlagsWait(evt_id, FLAG, osFlagsWaitAll, TIMEOUT_TICKS);
135 	zassert_equal(flags & FLAG, FLAG, "osEventFlagsWait failed unexpectedly");
136 
137 	/* set any single flag */
138 	flags = osEventFlagsSet(evt_id, FLAG1);
139 	zassert_equal(flags & FLAG1, FLAG1, "set any flag failed");
140 
141 	flags = osEventFlagsWait(evt_id, FLAG1, osFlagsWaitAny, TIMEOUT_TICKS);
142 	zassert_equal(flags & FLAG1, FLAG1, "osEventFlagsWait failed unexpectedly");
143 
144 	/* validate by passing invalid parameters */
145 	zassert_equal(osEventFlagsSet(NULL, 0), osFlagsErrorParameter,
146 		      "Invalid event Flags ID is unexpectedly working!");
147 	zassert_equal(osEventFlagsSet(evt_id, 0x80010000), osFlagsErrorParameter,
148 		      "Event with MSB set is set unexpectedly");
149 
150 	zassert_equal(osEventFlagsClear(NULL, 0), osFlagsErrorParameter,
151 		      "Invalid event Flags ID is unexpectedly working!");
152 	zassert_equal(osEventFlagsClear(evt_id, 0x80010000), osFlagsErrorParameter,
153 		      "Event with MSB set is cleared unexpectedly");
154 
155 	/* cannot wait for Flag mask with MSB set */
156 	zassert_equal(osEventFlagsWait(evt_id, 0x80010000, osFlagsWaitAny, 0),
157 		      osFlagsErrorParameter, "EventFlagsWait passed unexpectedly");
158 }
159 
160 /* IRQ offload function handler to set event flag */
offload_function(const void * param)161 static void offload_function(const void *param)
162 {
163 	int flags;
164 
165 	/* Make sure we're in IRQ context */
166 	zassert_true(k_is_in_isr(), "Not in IRQ context!");
167 
168 	flags = osEventFlagsSet((osEventFlagsId_t)param, ISR_FLAG);
169 	zassert_equal(flags & ISR_FLAG, ISR_FLAG, "EventFlagsSet failed in ISR");
170 }
171 
test_event_from_isr(void * event_id)172 void test_event_from_isr(void *event_id)
173 {
174 	/**TESTPOINT: Offload to IRQ context*/
175 	irq_offload(offload_function, (const void *)event_id);
176 }
177 
178 static K_THREAD_STACK_DEFINE(test_stack3, STACKSZ);
179 static osThreadAttr_t thread3_attr = {
180 	.name = "Thread3",
181 	.stack_mem = &test_stack3,
182 	.stack_size = STACKSZ,
183 	.priority = osPriorityHigh,
184 };
185 
test_event_flags_isr(void)186 void test_event_flags_isr(void)
187 {
188 	osThreadId_t id;
189 	int flags;
190 	osEventFlagsId_t dummy_id = NULL;
191 
192 	id = osThreadNew(test_event_from_isr, evt_id, &thread3_attr);
193 	zassert_true(id != NULL, "Failed creating thread");
194 
195 	flags = osEventFlagsWait(dummy_id, ISR_FLAG, osFlagsWaitAll, TIMEOUT_TICKS);
196 	zassert_true(flags == osFlagsErrorParameter,
197 		     "Invalid event Flags ID is unexpectedly working!");
198 
199 	flags = osEventFlagsWait(evt_id, ISR_FLAG, osFlagsWaitAll, TIMEOUT_TICKS);
200 	zassert_equal((flags & ISR_FLAG), ISR_FLAG, "unexpected event flags value");
201 
202 	zassert_true(osEventFlagsDelete(dummy_id) == osErrorResource,
203 		     "Invalid event Flags ID is unexpectedly working!");
204 
205 	zassert_true(osEventFlagsDelete(evt_id) == osOK, "EventFlagsDelete failed");
206 }
ZTEST(cmsis_event_flags,test_event_flags)207 ZTEST(cmsis_event_flags, test_event_flags)
208 {
209 	/*
210 	 *These tests are order-dependent.
211 	 *They have to be executed in order.
212 	 *So put these tests in one ZTEST.
213 	 */
214 	test_event_flags_no_wait_timeout();
215 	test_event_flags_signalled();
216 	test_event_flags_isr();
217 }
218 
219 static struct cmsis_rtos_event_cb event_cb2;
220 static const osEventFlagsAttr_t event_flags_attrs2 = {
221 	.name = "Event2",
222 	.attr_bits = 0,
223 	.cb_mem = &event_cb2,
224 	.cb_size = sizeof(event_cb2),
225 };
ZTEST(cmsis_event_flags,test_event_flags_static_allocation)226 ZTEST(cmsis_event_flags, test_event_flags_static_allocation)
227 {
228 	osEventFlagsId_t id;
229 
230 	id = osEventFlagsNew(&event_flags_attrs2);
231 	zassert_not_null(id, "Failed creating event flags using static cb");
232 
233 	zassert_true(osEventFlagsDelete(evt_id) == osOK, "EventFlagsDelete failed");
234 }
235 ZTEST_SUITE(cmsis_event_flags, NULL, NULL, NULL, NULL, NULL);
236