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 if (attr->name == NULL) {
54 strncpy(events->name, init_event_flags_attrs.name, sizeof(events->name) - 1);
55 } else {
56 strncpy(events->name, attr->name, sizeof(events->name) - 1);
57 }
58
59 return (osEventFlagsId_t)events;
60 }
61
62 /**
63 * @brief Set the specified Event Flags.
64 */
osEventFlagsSet(osEventFlagsId_t ef_id,uint32_t flags)65 uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
66 {
67 struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
68 unsigned int key;
69
70 if ((ef_id == NULL) || (flags & osFlagsError)) {
71 return osFlagsErrorParameter;
72 }
73
74 key = irq_lock();
75 events->signal_results |= flags;
76 irq_unlock(key);
77
78 k_poll_signal_raise(&events->poll_signal, DONT_CARE);
79
80 return events->signal_results;
81 }
82
83 /**
84 * @brief Clear the specified Event Flags.
85 */
osEventFlagsClear(osEventFlagsId_t ef_id,uint32_t flags)86 uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
87 {
88 struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
89 unsigned int key;
90 uint32_t sig;
91
92 if ((ef_id == NULL) || (flags & osFlagsError)) {
93 return osFlagsErrorParameter;
94 }
95
96 key = irq_lock();
97 sig = events->signal_results;
98 events->signal_results &= ~(flags);
99 irq_unlock(key);
100
101 return sig;
102 }
103
104 /**
105 * @brief Wait for one or more Event Flags to become signaled.
106 */
osEventFlagsWait(osEventFlagsId_t ef_id,uint32_t flags,uint32_t options,uint32_t timeout)107 uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options,
108 uint32_t timeout)
109 {
110 struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
111 int retval, key;
112 uint32_t sig;
113 k_timeout_t poll_timeout;
114 uint64_t time_stamp_start, ticks_elapsed;
115 bool flags_are_set;
116
117 /* Can be called from ISRs only if timeout is set to 0 */
118 if (timeout > 0 && k_is_in_isr()) {
119 return osFlagsErrorUnknown;
120 }
121
122 if ((ef_id == NULL) || (flags & osFlagsError)) {
123 return osFlagsErrorParameter;
124 }
125
126 time_stamp_start = (uint64_t)k_uptime_ticks();
127
128 for (;;) {
129
130 flags_are_set = false;
131
132 key = irq_lock();
133
134 if (options & osFlagsWaitAll) {
135 /* Check if all events we are waiting on have
136 * been signalled
137 */
138 if ((events->signal_results & flags) == flags) {
139 flags_are_set = true;
140 }
141 } else {
142 /* Check if any of events we are waiting on have
143 * been signalled
144 */
145 if (events->signal_results & flags) {
146 flags_are_set = true;
147 }
148 }
149
150 if (flags_are_set) {
151 sig = events->signal_results;
152
153 if (!(options & osFlagsNoClear)) {
154 /* Clear signal flags as the thread is ready now */
155 events->signal_results &= ~(flags);
156 }
157
158 irq_unlock(key);
159
160 break;
161 }
162
163 /* Reset the states to facilitate the next trigger */
164 events->poll_event.signal->signaled = 0U;
165 events->poll_event.state = K_POLL_STATE_NOT_READY;
166
167 irq_unlock(key);
168
169 if (timeout == 0) {
170 return osFlagsErrorTimeout;
171 } else if (timeout == osWaitForever) {
172 poll_timeout = Z_FOREVER;
173 } else {
174 /* If we need to wait on more signals, we need to
175 * adjust the timeout value accordingly based on
176 * the time that has already elapsed.
177 */
178 ticks_elapsed = (uint64_t)k_uptime_ticks() - time_stamp_start;
179
180 if (ticks_elapsed < (uint64_t)timeout) {
181 poll_timeout = Z_TIMEOUT_TICKS(
182 (k_ticks_t)(timeout - (uint32_t)ticks_elapsed));
183 } else {
184 return osFlagsErrorTimeout;
185 }
186 }
187
188 retval = k_poll(&events->poll_event, 1, poll_timeout);
189
190 if (retval == -EAGAIN) {
191 /* k_poll signaled timeout. */
192 return osFlagsErrorTimeout;
193 } else if (retval != 0) {
194 return osFlagsErrorUnknown;
195 }
196
197 /* retval is zero.
198 * k_poll found some raised signal then loop again and check flags.
199 */
200 __ASSERT(events->poll_event.state == K_POLL_STATE_SIGNALED,
201 "event state not signalled!");
202 __ASSERT(events->poll_event.signal->signaled == 1U, "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 cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)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 cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)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 cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)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 if (events->is_cb_dynamic_allocation) {
255 k_mem_slab_free(&cmsis_rtos_event_cb_slab, (void *)events);
256 }
257 return osOK;
258 }
259