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