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 		switch (timeout) {
113 		case 0:
114 			retval = k_poll(&tid->poll_event, 1, K_NO_WAIT);
115 			break;
116 		case osWaitForever:
117 			retval = k_poll(&tid->poll_event, 1, K_FOREVER);
118 			break;
119 		default:
120 			retval = k_poll(&tid->poll_event, 1, K_MSEC(timeout_ms));
121 			break;
122 		}
123 
124 		switch (retval) {
125 		case 0:
126 			break;
127 		case -EAGAIN:
128 			return osFlagsErrorTimeout;
129 		default:
130 			return osFlagsErrorUnknown;
131 		}
132 
133 		__ASSERT(tid->poll_event.state == K_POLL_STATE_SIGNALED,
134 			 "event state not signalled!");
135 		__ASSERT(tid->poll_event.signal->signaled == 1U, "event signaled is not 1");
136 
137 		/* Reset the states to facilitate the next trigger */
138 		tid->poll_event.signal->signaled = 0U;
139 		tid->poll_event.state = K_POLL_STATE_NOT_READY;
140 
141 		if (options & osFlagsWaitAll) {
142 			/* Check if all events we are waiting on have
143 			 * been signalled
144 			 */
145 			if ((tid->signal_results & flags) == flags) {
146 				break;
147 			}
148 
149 			/* If we need to wait on more signals, we need to
150 			 * adjust the timeout value accordingly based on
151 			 * the time that has already elapsed.
152 			 */
153 			hwclk_cycles_delta = (uint64_t)k_cycle_get_32() - time_stamp_start;
154 
155 			time_delta_ns = (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta);
156 
157 			time_delta_ms = (uint32_t)time_delta_ns / NSEC_PER_MSEC;
158 
159 			if (timeout_ms > time_delta_ms) {
160 				timeout_ms -= time_delta_ms;
161 			} else {
162 				timeout_ms = 0U;
163 			}
164 		} else {
165 			break;
166 		}
167 	}
168 
169 	sig = tid->signal_results;
170 	if (!(options & osFlagsNoClear)) {
171 
172 		/* Clear signal flags as the thread is ready now */
173 		key = irq_lock();
174 		tid->signal_results &= ~(flags);
175 		irq_unlock(key);
176 	}
177 
178 	return sig;
179 }
180