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