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