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