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 #include "wrapper.h"
11 
12 K_MEM_SLAB_DEFINE(cmsis_rtos_msgq_cb_slab, sizeof(struct cmsis_rtos_msgq_cb),
13 		  CONFIG_CMSIS_V2_MSGQ_MAX_COUNT, 4);
14 
15 static const osMessageQueueAttr_t init_msgq_attrs = {
16 	.name = "ZephyrMsgQ",
17 	.attr_bits = 0,
18 	.cb_mem = NULL,
19 	.cb_size = 0,
20 	.mq_mem = NULL,
21 	.mq_size = 0,
22 };
23 
24 /**
25  * @brief Create and Initialize Message queue.
26  */
osMessageQueueNew(uint32_t msg_count,uint32_t msg_size,const osMessageQueueAttr_t * attr)27 osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size,
28 				     const osMessageQueueAttr_t *attr)
29 {
30 	struct cmsis_rtos_msgq_cb *msgq;
31 
32 	BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE,
33 		     "heap must be configured to be at least the max dynamic size");
34 
35 	if (k_is_in_isr()) {
36 		return NULL;
37 	}
38 
39 	if ((attr != NULL) && (attr->mq_size < msg_count * msg_size)) {
40 		return NULL;
41 	}
42 
43 	if (attr == NULL) {
44 		attr = &init_msgq_attrs;
45 	}
46 
47 	if (attr->cb_mem != NULL) {
48 		__ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_msgq_cb), "Invalid cb_size\n");
49 		msgq = (struct cmsis_rtos_msgq_cb *)attr->cb_mem;
50 	} else if (k_mem_slab_alloc(&cmsis_rtos_msgq_cb_slab, (void **)&msgq, K_MSEC(100)) != 0) {
51 		return NULL;
52 	}
53 	(void)memset(msgq, 0, sizeof(struct cmsis_rtos_msgq_cb));
54 	msgq->is_cb_dynamic_allocation = attr->cb_mem == NULL;
55 
56 	if (attr->mq_mem == NULL) {
57 		__ASSERT((msg_count * msg_size) <= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE,
58 			 "message queue size exceeds dynamic maximum");
59 
60 #if (K_HEAP_MEM_POOL_SIZE > 0)
61 		msgq->pool = k_calloc(msg_count, msg_size);
62 		if (msgq->pool == NULL) {
63 			if (msgq->is_cb_dynamic_allocation) {
64 				k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq);
65 			}
66 			return NULL;
67 		}
68 		msgq->is_dynamic_allocation = TRUE;
69 #else
70 		if (msgq->is_cb_dynamic_allocation) {
71 			k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq);
72 		}
73 		return NULL;
74 #endif
75 	} else {
76 		msgq->pool = attr->mq_mem;
77 		msgq->is_dynamic_allocation = FALSE;
78 	}
79 
80 	k_msgq_init(&msgq->z_msgq, msgq->pool, msg_size, msg_count);
81 
82 	if (attr->name == NULL) {
83 		strncpy(msgq->name, init_msgq_attrs.name, sizeof(msgq->name) - 1);
84 	} else {
85 		strncpy(msgq->name, attr->name, sizeof(msgq->name) - 1);
86 	}
87 
88 	return (osMessageQueueId_t)(msgq);
89 }
90 
91 /**
92  * @brief Put a message to a Queue.
93  */
osMessageQueuePut(osMessageQueueId_t msgq_id,const void * msg_ptr,uint8_t msg_prio,uint32_t timeout)94 osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, uint8_t msg_prio,
95 			     uint32_t timeout)
96 {
97 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
98 	int retval;
99 
100 	ARG_UNUSED(msg_prio);
101 
102 	if (msgq == NULL) {
103 		return osErrorParameter;
104 	}
105 
106 	/* Can be called from ISRs only if timeout is set to 0 */
107 	if (timeout > 0 && k_is_in_isr()) {
108 		return osErrorParameter;
109 	}
110 
111 	if (timeout == 0U) {
112 		retval = k_msgq_put(&msgq->z_msgq, (void *)msg_ptr, K_NO_WAIT);
113 	} else if (timeout == osWaitForever) {
114 		retval = k_msgq_put(&msgq->z_msgq, (void *)msg_ptr, K_FOREVER);
115 	} else {
116 		retval = k_msgq_put(&msgq->z_msgq, (void *)msg_ptr, K_TICKS(timeout));
117 	}
118 
119 	if (retval == 0) {
120 		return osOK;
121 	} else if (retval == -EAGAIN) {
122 		return osErrorTimeout;
123 	} else {
124 		return osErrorResource;
125 	}
126 }
127 
128 /**
129  * @brief Get a message or Wait for a Message from a Queue.
130  */
osMessageQueueGet(osMessageQueueId_t msgq_id,void * msg_ptr,uint8_t * msg_prio,uint32_t timeout)131 osStatus_t osMessageQueueGet(osMessageQueueId_t msgq_id, void *msg_ptr, uint8_t *msg_prio,
132 			     uint32_t timeout)
133 {
134 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
135 	int retval;
136 
137 	ARG_UNUSED(msg_prio);
138 
139 	if (msgq == NULL) {
140 		return osErrorParameter;
141 	}
142 
143 	/* Can be called from ISRs only if timeout is set to 0 */
144 	if (timeout > 0 && k_is_in_isr()) {
145 		return osErrorParameter;
146 	}
147 
148 	if (timeout == 0U) {
149 		retval = k_msgq_get(&msgq->z_msgq, msg_ptr, K_NO_WAIT);
150 	} else if (timeout == osWaitForever) {
151 		retval = k_msgq_get(&msgq->z_msgq, msg_ptr, K_FOREVER);
152 	} else {
153 		retval = k_msgq_get(&msgq->z_msgq, msg_ptr, K_TICKS(timeout));
154 	}
155 
156 	if (retval == 0) {
157 		return osOK;
158 	} else if (retval == -EAGAIN) {
159 		return osErrorTimeout;
160 	} else if (retval == -ENOMSG) {
161 		return osErrorResource;
162 	}
163 
164 	return osOK;
165 }
166 
167 /**
168  * @brief Get maximum number of messages in a Message Queue.
169  */
osMessageQueueGetCapacity(osMessageQueueId_t msgq_id)170 uint32_t osMessageQueueGetCapacity(osMessageQueueId_t msgq_id)
171 {
172 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
173 
174 	if (msgq == NULL) {
175 		return 0;
176 	} else {
177 		return msgq->z_msgq.max_msgs;
178 	}
179 }
180 
181 /**
182  * @brief Get maximum message size in a Message Queue.
183  */
osMessageQueueGetMsgSize(osMessageQueueId_t msgq_id)184 uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t msgq_id)
185 {
186 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
187 
188 	if (msgq == NULL) {
189 		return 0;
190 	} else {
191 		return msgq->z_msgq.msg_size;
192 	}
193 }
194 
195 /**
196  * @brief Get number of queued messages in a Message Queue.
197  */
osMessageQueueGetCount(osMessageQueueId_t msgq_id)198 uint32_t osMessageQueueGetCount(osMessageQueueId_t msgq_id)
199 {
200 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
201 
202 	if (msgq == NULL) {
203 		return 0;
204 	} else {
205 		return k_msgq_num_used_get(&msgq->z_msgq);
206 	}
207 }
208 
209 /**
210  * @brief Get number of available slots for messages in a Message Queue.
211  */
osMessageQueueGetSpace(osMessageQueueId_t msgq_id)212 uint32_t osMessageQueueGetSpace(osMessageQueueId_t msgq_id)
213 {
214 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
215 
216 	if (msgq == NULL) {
217 		return 0;
218 	} else {
219 		return k_msgq_num_free_get(&msgq->z_msgq);
220 	}
221 }
222 
223 /**
224  * @brief Get name of a Message Queue object.
225  */
osMessageQueueGetName(osMessageQueueId_t msgq_id)226 const char *osMessageQueueGetName(osMessageQueueId_t msgq_id)
227 {
228 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
229 
230 	if (!k_is_in_isr() && (msgq_id != NULL)) {
231 		return msgq->name;
232 	} else {
233 		return NULL;
234 	}
235 }
236 
237 /**
238  * @brief Reset a Message Queue to initial empty state.
239  */
osMessageQueueReset(osMessageQueueId_t msgq_id)240 osStatus_t osMessageQueueReset(osMessageQueueId_t msgq_id)
241 {
242 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
243 
244 	if (msgq == NULL) {
245 		return osErrorParameter;
246 	}
247 
248 	if (k_is_in_isr()) {
249 		return osErrorISR;
250 	}
251 
252 	/* The status code "osErrorResource" (the message queue specified by
253 	 * parameter msgq_id is in an invalid message queue state) is not
254 	 * supported in Zephyr.
255 	 */
256 
257 	k_msgq_purge(&msgq->z_msgq);
258 
259 	return osOK;
260 }
261 
262 /**
263  * @brief Delete a Message Queue object.
264  */
osMessageQueueDelete(osMessageQueueId_t msgq_id)265 osStatus_t osMessageQueueDelete(osMessageQueueId_t msgq_id)
266 {
267 	struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id;
268 
269 	if (msgq == NULL) {
270 		return osErrorParameter;
271 	}
272 
273 	if (k_is_in_isr()) {
274 		return osErrorISR;
275 	}
276 
277 	/* The status code "osErrorResource" (the message queue specified by
278 	 * parameter msgq_id is in an invalid message queue state) is not
279 	 * supported in Zephyr.
280 	 */
281 
282 	if (msgq->is_dynamic_allocation) {
283 		k_free(msgq->pool);
284 	}
285 	if (msgq->is_cb_dynamic_allocation) {
286 		k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq);
287 	}
288 	return osOK;
289 }
290