1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include "wrapper.h"
10 
11 K_MEM_SLAB_DEFINE(cv2_event_flags_slab, sizeof(struct cv2_event_flags),
12 		  CONFIG_CMSIS_V2_EVT_FLAGS_MAX_COUNT, 4);
13 
14 static const osEventFlagsAttr_t init_event_flags_attrs = {
15 	.name = "ZephyrEvent",
16 	.attr_bits = 0,
17 	.cb_mem = NULL,
18 	.cb_size = 0,
19 };
20 
21 #define DONT_CARE        (0)
22 
23 /**
24  * @brief Create and Initialize an Event Flags object.
25  */
osEventFlagsNew(const osEventFlagsAttr_t * attr)26 osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
27 {
28 	struct cv2_event_flags *events;
29 
30 	if (k_is_in_isr()) {
31 		return NULL;
32 	}
33 
34 	if (attr == NULL) {
35 		attr = &init_event_flags_attrs;
36 	}
37 
38 	if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, K_MSEC(100))
39 		== 0) {
40 		memset(events, 0, sizeof(struct cv2_event_flags));
41 	} else {
42 		return NULL;
43 	}
44 
45 	k_poll_signal_init(&events->poll_signal);
46 	k_poll_event_init(&events->poll_event, K_POLL_TYPE_SIGNAL,
47 			  K_POLL_MODE_NOTIFY_ONLY, &events->poll_signal);
48 	events->signal_results = 0U;
49 
50 	if (attr->name == NULL) {
51 		strncpy(events->name, init_event_flags_attrs.name,
52 			sizeof(events->name) - 1);
53 	} else {
54 		strncpy(events->name, attr->name, sizeof(events->name) - 1);
55 	}
56 
57 	return (osEventFlagsId_t)events;
58 }
59 
60 /**
61  * @brief Set the specified Event Flags.
62  */
osEventFlagsSet(osEventFlagsId_t ef_id,uint32_t flags)63 uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
64 {
65 	struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
66 	unsigned int key;
67 
68 	if ((ef_id == NULL) || (flags & osFlagsError)) {
69 		return osFlagsErrorParameter;
70 	}
71 
72 	key = irq_lock();
73 	events->signal_results |= flags;
74 	irq_unlock(key);
75 
76 	k_poll_signal_raise(&events->poll_signal, DONT_CARE);
77 
78 	return events->signal_results;
79 }
80 
81 /**
82  * @brief Clear the specified Event Flags.
83  */
osEventFlagsClear(osEventFlagsId_t ef_id,uint32_t flags)84 uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
85 {
86 	struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
87 	unsigned int key;
88 	uint32_t sig;
89 
90 	if ((ef_id == NULL) || (flags & osFlagsError)) {
91 		return osFlagsErrorParameter;
92 	}
93 
94 	key = irq_lock();
95 	sig = events->signal_results;
96 	events->signal_results &= ~(flags);
97 	irq_unlock(key);
98 
99 	return sig;
100 }
101 
102 /**
103  * @brief Wait for one or more Event Flags to become signaled.
104  */
osEventFlagsWait(osEventFlagsId_t ef_id,uint32_t flags,uint32_t options,uint32_t timeout)105 uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags,
106 			  uint32_t options, uint32_t timeout)
107 {
108 	struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
109 	int retval, key;
110 	uint32_t sig;
111 	k_timeout_t poll_timeout;
112 	uint64_t time_stamp_start, ticks_elapsed;
113 	bool flags_are_set;
114 
115 	/* Can be called from ISRs only if timeout is set to 0 */
116 	if (timeout > 0 && k_is_in_isr()) {
117 		return osFlagsErrorUnknown;
118 	}
119 
120 	if ((ef_id == NULL) || (flags & osFlagsError)) {
121 		return osFlagsErrorParameter;
122 	}
123 
124 	time_stamp_start = (uint64_t)k_uptime_ticks();
125 
126 	for (;;) {
127 
128 		flags_are_set = false;
129 
130 		key = irq_lock();
131 
132 		if (options & osFlagsWaitAll) {
133 			/* Check if all events we are waiting on have
134 			 * been signalled
135 			 */
136 			if ((events->signal_results & flags) == flags) {
137 				flags_are_set = true;
138 			}
139 		} else {
140 			/* Check if any of events we are waiting on have
141 			 * been signalled
142 			 */
143 			if (events->signal_results & flags) {
144 				flags_are_set = true;
145 			}
146 		}
147 
148 		if (flags_are_set) {
149 			sig = events->signal_results;
150 
151 			if (!(options & osFlagsNoClear)) {
152 				/* Clear signal flags as the thread is ready now */
153 				events->signal_results &= ~(flags);
154 			}
155 
156 			irq_unlock(key);
157 
158 			break;
159 		}
160 
161 		/* Reset the states to facilitate the next trigger */
162 		events->poll_event.signal->signaled = 0U;
163 		events->poll_event.state = K_POLL_STATE_NOT_READY;
164 
165 		irq_unlock(key);
166 
167 		if (timeout == 0) {
168 			return osFlagsErrorTimeout;
169 		} else if (timeout == osWaitForever) {
170 			poll_timeout = Z_FOREVER;
171 		} else {
172 			/* If we need to wait on more signals, we need to
173 			 * adjust the timeout value accordingly based on
174 			 * the time that has already elapsed.
175 			 */
176 			ticks_elapsed =
177 				(uint64_t)k_uptime_ticks() - time_stamp_start;
178 
179 			if (ticks_elapsed < (uint64_t)timeout) {
180 				poll_timeout = Z_TIMEOUT_TICKS((k_ticks_t)(
181 					timeout - (uint32_t)ticks_elapsed));
182 			} else {
183 				return osFlagsErrorTimeout;
184 			}
185 		}
186 
187 		retval = k_poll(&events->poll_event, 1, poll_timeout);
188 
189 		if (retval == -EAGAIN) {
190 			/* k_poll signaled timeout. */
191 			return osFlagsErrorTimeout;
192 		} else if (retval != 0) {
193 			return osFlagsErrorUnknown;
194 		}
195 
196 		/* retval is zero.
197 		 * k_poll found some raised signal then loop again and check flags.
198 		 */
199 		__ASSERT(events->poll_event.state == K_POLL_STATE_SIGNALED,
200 			 "event state not signalled!");
201 		__ASSERT(events->poll_event.signal->signaled == 1U,
202 			 "event signaled is not 1");
203 	}
204 
205 	return sig;
206 }
207 
208 /**
209  * @brief Get name of an Event Flags object.
210  */
osEventFlagsGetName(osEventFlagsId_t ef_id)211 const char *osEventFlagsGetName(osEventFlagsId_t ef_id)
212 {
213 	struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
214 
215 	if (!k_is_in_isr() && (ef_id != NULL)) {
216 		return events->name;
217 	} else {
218 		return NULL;
219 	}
220 }
221 
222 /**
223  * @brief Get the current Event Flags.
224  */
osEventFlagsGet(osEventFlagsId_t ef_id)225 uint32_t osEventFlagsGet(osEventFlagsId_t ef_id)
226 {
227 	struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
228 
229 	if (ef_id == NULL) {
230 		return 0;
231 	}
232 
233 	return events->signal_results;
234 }
235 
236 /**
237  * @brief Delete an Event Flags object.
238  */
osEventFlagsDelete(osEventFlagsId_t ef_id)239 osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id)
240 {
241 	struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id;
242 
243 	if (ef_id == NULL) {
244 		return osErrorResource;
245 	}
246 
247 	if (k_is_in_isr()) {
248 		return osErrorISR;
249 	}
250 
251 	/* The status code "osErrorParameter" (the value of the parameter
252 	 * ef_id is incorrect) is not supported in Zephyr.
253 	 */
254 
255 	k_mem_slab_free(&cv2_event_flags_slab, (void *)&events);
256 
257 	return osOK;
258 }
259