1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel_structs.h>
8 #include <zephyr/portability/cmsis_types.h>
9 #include "wrapper.h"
10
11 #define DONT_CARE (0)
12
13 /**
14 * @brief Set the specified Thread Flags of a thread.
15 */
osThreadFlagsSet(osThreadId_t thread_id,uint32_t flags)16 uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags)
17 {
18 unsigned int key;
19 struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id;
20
21 if ((thread_id == NULL) || (is_cmsis_rtos_v2_thread(thread_id) == NULL) ||
22 (flags & 0x80000000)) {
23 return osFlagsErrorParameter;
24 }
25
26 key = irq_lock();
27 tid->signal_results |= flags;
28 irq_unlock(key);
29
30 k_poll_signal_raise(&tid->poll_signal, DONT_CARE);
31
32 return tid->signal_results;
33 }
34
35 /**
36 * @brief Get the current Thread Flags of current running thread.
37 */
osThreadFlagsGet(void)38 uint32_t osThreadFlagsGet(void)
39 {
40 struct cmsis_rtos_thread_cb *tid;
41
42 if (k_is_in_isr()) {
43 return 0;
44 }
45
46 tid = (struct cmsis_rtos_thread_cb *)osThreadGetId();
47 if (tid == NULL) {
48 return 0;
49 } else {
50 return tid->signal_results;
51 }
52 }
53
54 /**
55 * @brief Clear the specified Thread Flags of current running thread.
56 */
osThreadFlagsClear(uint32_t flags)57 uint32_t osThreadFlagsClear(uint32_t flags)
58 {
59 struct cmsis_rtos_thread_cb *tid;
60 int sig, key;
61
62 if (k_is_in_isr()) {
63 return osFlagsErrorUnknown;
64 }
65
66 if (flags & 0x80000000) {
67 return osFlagsErrorParameter;
68 }
69
70 tid = (struct cmsis_rtos_thread_cb *)osThreadGetId();
71 if (tid == NULL) {
72 return osFlagsErrorUnknown;
73 }
74
75 key = irq_lock();
76 sig = tid->signal_results;
77 tid->signal_results &= ~(flags);
78 irq_unlock(key);
79
80 return sig;
81 }
82
83 /**
84 * @brief Wait for one or more Thread Flags of the current running thread to
85 * become signalled.
86 */
osThreadFlagsWait(uint32_t flags,uint32_t options,uint32_t timeout)87 uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
88 {
89 struct cmsis_rtos_thread_cb *tid;
90 int retval, key;
91 uint32_t sig;
92 uint32_t time_delta_ms, timeout_ms = k_ticks_to_ms_floor64(timeout);
93 uint64_t time_stamp_start, hwclk_cycles_delta, time_delta_ns;
94
95 if (k_is_in_isr()) {
96 return osFlagsErrorUnknown;
97 }
98
99 if (flags & 0x80000000) {
100 return osFlagsErrorParameter;
101 }
102
103 tid = (struct cmsis_rtos_thread_cb *)osThreadGetId();
104 if (tid == NULL) {
105 return osFlagsErrorUnknown;
106 }
107
108 for (;;) {
109
110 time_stamp_start = (uint64_t)k_cycle_get_32();
111
112 sig = tid->signal_results & flags;
113
114 if (options & osFlagsWaitAll) {
115 /* Check if all events we are waiting on have
116 * been signalled
117 */
118 if (sig == flags) {
119 break;
120 }
121 } else {
122 /* Check if any events we are waiting on have
123 * been signalled
124 */
125 if (sig != 0) {
126 break;
127 }
128 }
129
130 switch (timeout) {
131 case 0:
132 retval = k_poll(&tid->poll_event, 1, K_NO_WAIT);
133 break;
134 case osWaitForever:
135 retval = k_poll(&tid->poll_event, 1, K_FOREVER);
136 break;
137 default:
138 retval = k_poll(&tid->poll_event, 1, K_MSEC(timeout_ms));
139 break;
140 }
141
142 switch (retval) {
143 case 0:
144 break;
145 case -EAGAIN:
146 return osFlagsErrorTimeout;
147 default:
148 return osFlagsErrorUnknown;
149 }
150
151 __ASSERT(tid->poll_event.state == K_POLL_STATE_SIGNALED,
152 "event state not signalled!");
153 __ASSERT(tid->poll_event.signal->signaled == 1U, "event signaled is not 1");
154
155 /* Reset the states to facilitate the next trigger */
156 tid->poll_event.signal->signaled = 0U;
157 tid->poll_event.state = K_POLL_STATE_NOT_READY;
158
159 /* If we need to wait on more signals, we need to
160 * adjust the timeout value accordingly based on
161 * the time that has already elapsed.
162 */
163 hwclk_cycles_delta = (uint64_t)k_cycle_get_32() - time_stamp_start;
164
165 time_delta_ns = (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta);
166
167 time_delta_ms = (uint32_t)time_delta_ns / NSEC_PER_MSEC;
168
169 if (timeout_ms > time_delta_ms) {
170 timeout_ms -= time_delta_ms;
171 } else {
172 timeout_ms = 0U;
173 }
174 }
175
176 if (!(options & osFlagsNoClear)) {
177 /* Clear signal flags as the thread is ready now */
178 key = irq_lock();
179 tid->signal_results &= ~(sig);
180 irq_unlock(key);
181 }
182
183 return sig;
184 }
185