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