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 <cmsis_os2.h>
10 
11 #include <zephyr/irq_offload.h>
12 #include <zephyr/kernel_structs.h>
13 
14 #define TIMEOUT_TICKS (10)
15 #define FLAG1         (0x00000020)
16 #define FLAG2         (0x00000004)
17 #define FLAG          (FLAG1 | FLAG2)
18 #define ISR_FLAG      (0x50)
19 #define STACKSZ       CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE
20 
thread1(void * arg)21 static void thread1(void *arg)
22 {
23 	uint32_t flags;
24 
25 	/* wait for FLAG1. It should return immediately as it is
26 	 * already triggered.
27 	 */
28 	flags = osThreadFlagsWait(FLAG1, osFlagsWaitAny | osFlagsNoClear, 0);
29 	zassert_equal(flags & FLAG1, FLAG1, "");
30 
31 	/* Since the flags are not cleared automatically in the previous step,
32 	 * we should be able to get the same flags upon query below.
33 	 */
34 	flags = osThreadFlagsGet();
35 	zassert_equal(flags & FLAG1, FLAG1, "");
36 
37 	/* Clear the Flag explicitly */
38 	flags = osThreadFlagsClear(FLAG1);
39 	zassert_not_equal(flags, osFlagsErrorParameter, "ThreadFlagsClear failed");
40 
41 	/* wait for FLAG1. It should timeout here as the flag
42 	 * though triggered, gets cleared in the previous step.
43 	 */
44 	flags = osThreadFlagsWait(FLAG1, osFlagsWaitAny, TIMEOUT_TICKS);
45 	zassert_equal(flags, osFlagsErrorTimeout, "ThreadFlagsWait failed");
46 }
47 
thread2(void * arg)48 static void thread2(void *arg)
49 {
50 	uint32_t flags;
51 
52 	flags = osThreadFlagsWait(FLAG, osFlagsWaitAll, TIMEOUT_TICKS);
53 	zassert_equal(flags & FLAG, FLAG, "osThreadFlagsWait failed unexpectedly");
54 
55 	/* validate by passing invalid parameters */
56 	zassert_equal(osThreadFlagsSet(NULL, 0), osFlagsErrorParameter,
57 		      "Invalid Thread Flags ID is unexpectedly working!");
58 	zassert_equal(osThreadFlagsSet(osThreadGetId(), 0x80010000), osFlagsErrorParameter,
59 		      "Thread with MSB set is set unexpectedly");
60 
61 	zassert_equal(osThreadFlagsClear(0x80010000), osFlagsErrorParameter,
62 		      "Thread with MSB set is cleared unexpectedly");
63 
64 	/* cannot wait for Flag mask with MSB set */
65 	zassert_equal(osThreadFlagsWait(0x80010000, osFlagsWaitAny, 0), osFlagsErrorParameter,
66 		      "ThreadFlagsWait passed unexpectedly");
67 }
68 
69 static K_THREAD_STACK_DEFINE(test_stack1, STACKSZ);
70 static osThreadAttr_t thread1_attr = {
71 	.name = "Thread1",
72 	.stack_mem = &test_stack1,
73 	.stack_size = STACKSZ,
74 	.priority = osPriorityHigh,
75 };
76 
77 static K_THREAD_STACK_DEFINE(test_stack2, STACKSZ);
78 static osThreadAttr_t thread2_attr = {
79 	.name = "Thread2",
80 	.stack_mem = &test_stack2,
81 	.stack_size = STACKSZ,
82 	.priority = osPriorityHigh,
83 };
84 
ZTEST(cmsis_thread_flags,test_thread_flags_no_wait_timeout)85 ZTEST(cmsis_thread_flags, test_thread_flags_no_wait_timeout)
86 {
87 	osThreadId_t id1;
88 	uint32_t flags;
89 
90 	id1 = osThreadNew(thread1, NULL, &thread1_attr);
91 	zassert_true(id1 != NULL, "Failed creating thread1");
92 
93 	flags = osThreadFlagsSet(id1, FLAG1);
94 	zassert_equal(flags & FLAG1, FLAG1, "");
95 
96 	/* Let id1 run to do the tests for Thread Flags */
97 	osDelay(TIMEOUT_TICKS);
98 }
99 
ZTEST(cmsis_thread_flags,test_thread_flags_signalled)100 ZTEST(cmsis_thread_flags, test_thread_flags_signalled)
101 {
102 	osThreadId_t id;
103 	uint32_t flags;
104 
105 	id = osThreadNew(thread2, osThreadGetId(), &thread2_attr);
106 	zassert_true(id != NULL, "Failed creating thread2");
107 
108 	flags = osThreadFlagsSet(id, FLAG1);
109 	zassert_equal(flags & FLAG1, FLAG1, "");
110 
111 	/* Let id run to do the tests for Thread Flags */
112 	osDelay(TIMEOUT_TICKS / 2);
113 
114 	flags = osThreadFlagsSet(id, FLAG2);
115 	zassert_equal(flags & FLAG2, FLAG2, "");
116 
117 	/* z_thread has a higher priority over the other threads.
118 	 * Hence, this thread needs to be put to sleep for thread2
119 	 * to become the active thread.
120 	 */
121 	osDelay(TIMEOUT_TICKS / 2);
122 }
123 
124 /* IRQ offload function handler to set Thread flag */
offload_function(const void * param)125 static void offload_function(const void *param)
126 {
127 	int flags;
128 
129 	/* Make sure we're in IRQ context */
130 	zassert_true(k_is_in_isr(), "Not in IRQ context!");
131 
132 	flags = osThreadFlagsSet((osThreadId_t)param, ISR_FLAG);
133 	zassert_equal(flags & ISR_FLAG, ISR_FLAG, "ThreadFlagsSet failed in ISR");
134 }
135 
test_thread_flags_from_isr(void * thread_id)136 void test_thread_flags_from_isr(void *thread_id)
137 {
138 	uint32_t flags;
139 
140 	/**TESTPOINT: Offload to IRQ context*/
141 	irq_offload(offload_function, (const void *)osThreadGetId());
142 
143 	flags = osThreadFlagsWait(ISR_FLAG, osFlagsWaitAll, TIMEOUT_TICKS);
144 	zassert_equal((flags & ISR_FLAG), ISR_FLAG, "unexpected Thread flags value");
145 }
146 
147 static K_THREAD_STACK_DEFINE(test_stack3, STACKSZ);
148 static osThreadAttr_t thread3_attr = {
149 	.name = "Thread3",
150 	.stack_mem = &test_stack3,
151 	.stack_size = STACKSZ,
152 	.priority = osPriorityHigh,
153 };
154 
ZTEST(cmsis_thread_flags,test_thread_flags_isr)155 ZTEST(cmsis_thread_flags, test_thread_flags_isr)
156 {
157 	osThreadId_t id;
158 
159 	id = osThreadNew(test_thread_flags_from_isr, osThreadGetId(), &thread3_attr);
160 	zassert_true(id != NULL, "Failed creating thread");
161 
162 	osDelay(TIMEOUT_TICKS);
163 }
164 ZTEST_SUITE(cmsis_thread_flags, NULL, NULL, NULL, NULL, NULL);
165