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 
47 	k_event_init(&events->z_event);
48 	events->is_cb_dynamic_allocation = (attr->cb_mem == NULL);
49 	events->name = (attr->name == NULL) ? init_event_flags_attrs.name : attr->name;
50 
51 	return (osEventFlagsId_t)events;
52 }
53 
54 /**
55  * @brief Set the specified Event Flags.
56  */
osEventFlagsSet(osEventFlagsId_t ef_id,uint32_t flags)57 uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
58 {
59 	struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
60 	uint32_t rv;
61 
62 	if ((ef_id == NULL) || (flags & osFlagsError)) {
63 		return osFlagsErrorParameter;
64 	}
65 
66 	rv = k_event_test(&events->z_event, 0xFFFFFFFF);
67 	k_event_post(&events->z_event, flags & ~rv);
68 
69 	return flags & ~rv;
70 }
71 
72 /**
73  * @brief Clear the specified Event Flags.
74  */
osEventFlagsClear(osEventFlagsId_t ef_id,uint32_t flags)75 uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
76 {
77 	struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
78 	uint32_t rv;
79 
80 	if ((ef_id == NULL) || (flags & osFlagsError)) {
81 		return osFlagsErrorParameter;
82 	}
83 
84 	rv = k_event_test(&events->z_event, 0xFFFFFFFF);
85 	k_event_clear(&events->z_event, flags & rv);
86 
87 	return rv;
88 }
89 
90 /**
91  * @brief Wait for one or more Event Flags to become signaled.
92  */
osEventFlagsWait(osEventFlagsId_t ef_id,uint32_t flags,uint32_t options,uint32_t timeout)93 uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options,
94 			  uint32_t timeout)
95 {
96 	struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
97 	uint32_t sub_opt = options & (osFlagsWaitAll | osFlagsNoClear);
98 	uint32_t rv;
99 	k_timeout_t event_timeout;
100 
101 	/*
102 	 * Return unknown error if called from ISR with a non-zero timeout
103 	 * or if flags is zero.
104 	 */
105 	if (((timeout > 0U) && k_is_in_isr()) || (flags == 0U)) {
106 		return osFlagsErrorUnknown;
107 	}
108 
109 	if ((ef_id == NULL) || (flags & osFlagsError)) {
110 		return osFlagsErrorParameter;
111 	}
112 
113 	if (timeout == osWaitForever) {
114 		event_timeout = K_FOREVER;
115 	} else if (timeout == 0U) {
116 		event_timeout = K_NO_WAIT;
117 	} else {
118 		event_timeout = K_TICKS(timeout);
119 	}
120 
121 	switch (sub_opt) {
122 	case osFlagsWaitAll | osFlagsNoClear:
123 		rv = k_event_wait_all(&events->z_event, flags, false, event_timeout);
124 		break;
125 	case osFlagsWaitAll:
126 		rv = k_event_wait_all_safe(&events->z_event, flags, false, event_timeout);
127 		break;
128 	case osFlagsNoClear:
129 		rv = k_event_wait(&events->z_event, flags, false, event_timeout);
130 		break;
131 	case 0:
132 		rv = k_event_wait_safe(&events->z_event, flags, false, event_timeout);
133 		break;
134 	default:
135 		__ASSERT_NO_MSG(0);
136 	}
137 
138 	if (rv != 0U) {
139 		return rv;
140 	}
141 
142 	return (timeout == 0U) ? osFlagsErrorResource : osFlagsErrorTimeout;
143 }
144 
145 /**
146  * @brief Get name of an Event Flags object.
147  * This function may be called from Interrupt Service Routines.
148  */
osEventFlagsGetName(osEventFlagsId_t ef_id)149 const char *osEventFlagsGetName(osEventFlagsId_t ef_id)
150 {
151 	struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
152 
153 	if (events == NULL) {
154 		return NULL;
155 	}
156 	return events->name;
157 }
158 
159 /**
160  * @brief Get the current Event Flags.
161  */
osEventFlagsGet(osEventFlagsId_t ef_id)162 uint32_t osEventFlagsGet(osEventFlagsId_t ef_id)
163 {
164 	struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
165 
166 	if (ef_id == NULL) {
167 		return 0;
168 	}
169 
170 	return k_event_test(&events->z_event, 0xFFFFFFFF);
171 }
172 
173 /**
174  * @brief Delete an Event Flags object.
175  */
osEventFlagsDelete(osEventFlagsId_t ef_id)176 osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id)
177 {
178 	struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id;
179 
180 	if (ef_id == NULL) {
181 		return osErrorResource;
182 	}
183 
184 	if (k_is_in_isr()) {
185 		return osErrorISR;
186 	}
187 
188 	/* The status code "osErrorParameter" (the value of the parameter
189 	 * ef_id is incorrect) is not supported in Zephyr.
190 	 */
191 	if (events->is_cb_dynamic_allocation) {
192 		k_mem_slab_free(&cmsis_rtos_event_cb_slab, (void *)events);
193 	}
194 	return osOK;
195 }
196