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