LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_q.c
Go to the documentation of this file.
1 /*
2 ************************************************************************************************************************
3 * uC/OS-III
4 * The Real-Time Kernel
5 *
6 * (c) Copyright 2009-2012; Micrium, Inc.; Weston, FL
7 * All rights reserved. Protected by international copyright laws.
8 *
9 * MESSAGE QUEUE MANAGEMENT
10 *
11 * File : OS_Q.C
12 * By : JJL
13 * Version : V3.03.00
14 *
15 * LICENSING TERMS:
16 * ---------------
17 * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
18 * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
19 * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
20 * application/product. We provide ALL the source code for your convenience and to help you
21 * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
22 * it commercially without paying a licensing fee.
23 *
24 * Knowledge of the source code may NOT be used to develop a similar product.
25 *
26 * Please help us continue to provide the embedded community with the finest software available.
27 * Your honesty is greatly appreciated.
28 *
29 * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
30 ************************************************************************************************************************
31 */
32 
33 #define MICRIUM_SOURCE
34 #include <os.h>
35 
36 #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
37 const CPU_CHAR *os_q__c = "$Id: $";
38 #endif
39 
40 
41 #if OS_CFG_Q_EN > 0u
42 /*
43 ************************************************************************************************************************
44 * CREATE A MESSAGE QUEUE
45 *
46 * Description: This function is called by your application to create a message queue. Message queues MUST be created
47 * before they can be used.
48 *
49 * Arguments : p_q is a pointer to the message queue
50 *
51 * p_name is a pointer to an ASCII string that will be used to name the message queue
52 *
53 * max_qty indicates the maximum size of the message queue (must be non-zero). Note that it's also not
54 * possible to have a size higher than the maximum number of OS_MSGs available.
55 *
56 * p_err is a pointer to a variable that will contain an error code returned by this function.
57 *
58 * OS_ERR_NONE the call was successful
59 * OS_ERR_CREATE_ISR can't create from an ISR
60 * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the Queue after you called
61 * OSSafetyCriticalStart().
62 * OS_ERR_NAME if 'p_name' is a NULL pointer
63 * OS_ERR_OBJ_CREATED if the message queue has already been created
64 * OS_ERR_OBJ_PTR_NULL if you passed a NULL pointer for 'p_q'
65 * OS_ERR_Q_SIZE if the size you specified is 0
66 *
67 * Returns : none
68 ************************************************************************************************************************
69 */
70 
71 void OSQCreate (OS_Q *p_q,
72  CPU_CHAR *p_name,
73  OS_MSG_QTY max_qty,
74  OS_ERR *p_err)
75 
76 {
77  CPU_SR_ALLOC();
78 
79 
80 
81 #ifdef OS_SAFETY_CRITICAL
82  if (p_err == (OS_ERR *)0) {
83  OS_SAFETY_CRITICAL_EXCEPTION();
84  return;
85  }
86 #endif
87 
88 #ifdef OS_SAFETY_CRITICAL_IEC61508
89  if (OSSafetyCriticalStartFlag == DEF_TRUE) {
91  return;
92  }
93 #endif
94 
95 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
96  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to be called from an ISR */
97  *p_err = OS_ERR_CREATE_ISR;
98  return;
99  }
100 #endif
101 
102 #if OS_CFG_ARG_CHK_EN > 0u
103  if (p_q == (OS_Q *)0) { /* Validate arguments */
104  *p_err = OS_ERR_OBJ_PTR_NULL;
105  return;
106  }
107  if (max_qty == (OS_MSG_QTY)0) { /* Cannot specify a zero size queue */
108  *p_err = OS_ERR_Q_SIZE;
109  return;
110  }
111 #endif
112 
114  p_q->Type = OS_OBJ_TYPE_Q; /* Mark the data structure as a message queue */
115  p_q->NamePtr = p_name;
116  OS_MsgQInit(&p_q->MsgQ, /* Initialize the queue */
117  max_qty);
118  OS_PendListInit(&p_q->PendList); /* Initialize the waiting list */
119 
120 #if OS_CFG_DBG_EN > 0u
121  OS_QDbgListAdd(p_q);
122 #endif
123  OSQQty++; /* One more queue created */
124 
126  *p_err = OS_ERR_NONE;
127 }
128 
129 /*$PAGE*/
130 /*
131 ************************************************************************************************************************
132 * DELETE A MESSAGE QUEUE
133 *
134 * Description: This function deletes a message queue and readies all tasks pending on the queue.
135 *
136 * Arguments : p_q is a pointer to the message queue you want to delete
137 *
138 * opt determines delete options as follows:
139 *
140 * OS_OPT_DEL_NO_PEND Delete the queue ONLY if no task pending
141 * OS_OPT_DEL_ALWAYS Deletes the queue even if tasks are waiting.
142 * In this case, all the tasks pending will be readied.
143 *
144 * p_err is a pointer to a variable that will contain an error code returned by this function.
145 *
146 * OS_ERR_NONE The call was successful and the queue was deleted
147 * OS_ERR_DEL_ISR If you tried to delete the queue from an ISR
148 * OS_ERR_OBJ_PTR_NULL if you pass a NULL pointer for 'p_q'
149 * OS_ERR_OBJ_TYPE if the message queue was not created
150 * OS_ERR_OPT_INVALID An invalid option was specified
151 * OS_ERR_TASK_WAITING One or more tasks were waiting on the queue
152 *
153 * Returns : == 0 if no tasks were waiting on the queue, or upon error.
154 * > 0 if one or more tasks waiting on the queue are now readied and informed.
155 *
156 * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the queue MUST
157 * check the return code of OSQPend().
158 *
159 * 2) OSQAccept() callers will not know that the intended queue has been deleted.
160 *
161 * 3) Because ALL tasks pending on the queue will be readied, you MUST be careful in applications where the
162 * queue is used for mutual exclusion because the resource(s) will no longer be guarded by the queue.
163 ************************************************************************************************************************
164 */
165 
166 #if OS_CFG_Q_DEL_EN > 0u
167 OS_OBJ_QTY OSQDel (OS_Q *p_q,
168  OS_OPT opt,
169  OS_ERR *p_err)
170 {
171  OS_OBJ_QTY cnt;
172  OS_OBJ_QTY nbr_tasks;
173  OS_PEND_DATA *p_pend_data;
174  OS_PEND_LIST *p_pend_list;
175  OS_TCB *p_tcb;
176  CPU_TS ts;
177  CPU_SR_ALLOC();
178 
179 
180 
181 #ifdef OS_SAFETY_CRITICAL
182  if (p_err == (OS_ERR *)0) {
183  OS_SAFETY_CRITICAL_EXCEPTION();
184  return ((OS_OBJ_QTY)0);
185  }
186 #endif
187 
188 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
189  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't delete a message queue from an ISR */
190  *p_err = OS_ERR_DEL_ISR;
191  return ((OS_OBJ_QTY)0);
192  }
193 #endif
194 
195 #if OS_CFG_ARG_CHK_EN > 0u
196  if (p_q == (OS_Q *)0) { /* Validate 'p_q' */
197  *p_err = OS_ERR_OBJ_PTR_NULL;
198  return ((OS_OBJ_QTY)0u);
199  }
200  switch (opt) { /* Validate 'opt' */
201  case OS_OPT_DEL_NO_PEND:
202  case OS_OPT_DEL_ALWAYS:
203  break;
204 
205  default:
206  *p_err = OS_ERR_OPT_INVALID;
207  return ((OS_OBJ_QTY)0u);
208  }
209 #endif
210 
211 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
212  if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
213  *p_err = OS_ERR_OBJ_TYPE;
214  return ((OS_OBJ_QTY)0);
215  }
216 #endif
217 
219  p_pend_list = &p_q->PendList;
220  cnt = p_pend_list->NbrEntries;
221  nbr_tasks = cnt;
222  switch (opt) {
223  case OS_OPT_DEL_NO_PEND: /* Delete message queue only if no task waiting */
224  if (nbr_tasks == (OS_OBJ_QTY)0) {
225 #if OS_CFG_DBG_EN > 0u
226  OS_QDbgListRemove(p_q);
227 #endif
228  OSQQty--;
229  OS_QClr(p_q);
231  *p_err = OS_ERR_NONE;
232  } else {
234  *p_err = OS_ERR_TASK_WAITING;
235  }
236  break;
237 
238  case OS_OPT_DEL_ALWAYS: /* Always delete the message queue */
240  ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
241  while (cnt > 0u) { /* Remove all tasks from the pend list */
242  p_pend_data = p_pend_list->HeadPtr;
243  p_tcb = p_pend_data->TCBPtr;
244  OS_PendObjDel((OS_PEND_OBJ *)((void *)p_q),
245  p_tcb,
246  ts);
247  cnt--;
248  }
249 #if OS_CFG_DBG_EN > 0u
250  OS_QDbgListRemove(p_q);
251 #endif
252  OSQQty--;
253  OS_QClr(p_q);
255  OSSched(); /* Find highest priority task ready to run */
256  *p_err = OS_ERR_NONE;
257  break;
258 
259  default:
261  *p_err = OS_ERR_OPT_INVALID;
262  break;
263  }
264  return (nbr_tasks);
265 }
266 #endif
267 
268 /*$PAGE*/
269 /*
270 ************************************************************************************************************************
271 * FLUSH QUEUE
272 *
273 * Description : This function is used to flush the contents of the message queue.
274 *
275 * Arguments : p_q is a pointer to the message queue to flush
276 *
277 * p_err is a pointer to a variable that will contain an error code returned by this function.
278 *
279 * OS_ERR_NONE upon success
280 * OS_ERR_FLUSH_ISR if you called this function from an ISR
281 * OS_ERR_OBJ_PTR_NULL If you passed a NULL pointer for 'p_q'
282 * OS_ERR_OBJ_TYPE If you didn't create the message queue
283 *
284 * Returns : The number of entries freed from the queue
285 *
286 * Note(s) : 1) You should use this function with great care because, when to flush the queue, you LOOSE the
287 * references to what the queue entries are pointing to and thus, you could cause 'memory leaks'. In
288 * other words, the data you are pointing to that's being referenced by the queue entries should, most
289 * likely, need to be de-allocated (i.e. freed).
290 ************************************************************************************************************************
291 */
292 
293 #if OS_CFG_Q_FLUSH_EN > 0u
294 OS_MSG_QTY OSQFlush (OS_Q *p_q,
295  OS_ERR *p_err)
296 {
297  OS_MSG_QTY entries;
298  CPU_SR_ALLOC();
299 
300 
301 
302 #ifdef OS_SAFETY_CRITICAL
303  if (p_err == (OS_ERR *)0) {
304  OS_SAFETY_CRITICAL_EXCEPTION();
305  return ((OS_MSG_QTY)0);
306  }
307 #endif
308 
309 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
310  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't flush a message queue from an ISR */
311  *p_err = OS_ERR_FLUSH_ISR;
312  return ((OS_MSG_QTY)0);
313  }
314 #endif
315 
316 #if OS_CFG_ARG_CHK_EN > 0u
317  if (p_q == (OS_Q *)0) { /* Validate arguments */
318  *p_err = OS_ERR_OBJ_PTR_NULL;
319  return ((OS_MSG_QTY)0);
320  }
321 #endif
322 
323 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
324  if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
325  *p_err = OS_ERR_OBJ_TYPE;
326  return ((OS_MSG_QTY)0);
327  }
328 #endif
329 
331  entries = OS_MsgQFreeAll(&p_q->MsgQ); /* Return all OS_MSGs to the OS_MSG pool */
333  *p_err = OS_ERR_NONE;
334  return ((OS_MSG_QTY)entries);
335 }
336 #endif
337 
338 /*$PAGE*/
339 /*
340 ************************************************************************************************************************
341 * PEND ON A QUEUE FOR A MESSAGE
342 *
343 * Description: This function waits for a message to be sent to a queue
344 *
345 * Arguments : p_q is a pointer to the message queue
346 *
347 * timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a
348 * message to arrive at the queue up to the amount of time specified by this argument. If you
349 * specify 0, however, your task will wait forever at the specified queue or, until a message
350 * arrives.
351 *
352 * opt determines whether the user wants to block if the queue is empty or not:
353 *
354 * OS_OPT_PEND_BLOCKING
355 * OS_OPT_PEND_NON_BLOCKING
356 *
357 * p_msg_size is a pointer to a variable that will receive the size of the message
358 *
359 * p_ts is a pointer to a variable that will receive the timestamp of when the message was
360 * received, pend aborted or the message queue deleted, If you pass a NULL pointer (i.e.
361 * (CPU_TS *)0) then you will not get the timestamp. In other words, passing a NULL pointer
362 * is valid and indicates that you don't need the timestamp.
363 *
364 * p_err is a pointer to a variable that will contain an error code returned by this function.
365 *
366 * OS_ERR_NONE The call was successful and your task received a message.
367 * OS_ERR_OBJ_PTR_NULL if you pass a NULL pointer for 'p_q'
368 * OS_ERR_OBJ_TYPE if the message queue was not created
369 * OS_ERR_PEND_ABORT the pend was aborted
370 * OS_ERR_PEND_ISR if you called this function from an ISR
371 * OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the queue was not empty
372 * OS_ERR_SCHED_LOCKED the scheduler is locked
373 * OS_ERR_TIMEOUT A message was not received within the specified timeout
374 * would lead to a suspension.
375 *
376 * Returns : != (void *)0 is a pointer to the message received
377 * == (void *)0 if you received a NULL pointer message or,
378 * if no message was received or,
379 * if 'p_q' is a NULL pointer or,
380 * if you didn't pass a pointer to a queue.
381 ************************************************************************************************************************
382 */
383 
384 void *OSQPend (OS_Q *p_q,
385  OS_TICK timeout,
386  OS_OPT opt,
387  OS_MSG_SIZE *p_msg_size,
388  CPU_TS *p_ts,
389  OS_ERR *p_err)
390 {
391  OS_PEND_DATA pend_data;
392  void *p_void;
393  CPU_SR_ALLOC();
394 
395 
396 
397 #ifdef OS_SAFETY_CRITICAL
398  if (p_err == (OS_ERR *)0) {
399  OS_SAFETY_CRITICAL_EXCEPTION();
400  return ((void *)0);
401  }
402 #endif
403 
404 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
405  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
406  *p_err = OS_ERR_PEND_ISR;
407  return ((void *)0);
408  }
409 #endif
410 
411 #if OS_CFG_ARG_CHK_EN > 0u
412  if (p_q == (OS_Q *)0) { /* Validate arguments */
413  *p_err = OS_ERR_OBJ_PTR_NULL;
414  return ((void *)0);
415  }
416  if (p_msg_size == (OS_MSG_SIZE *)0) {
417  *p_err = OS_ERR_PTR_INVALID;
418  return ((void *)0);
419  }
420  switch (opt) {
423  break;
424 
425  default:
426  *p_err = OS_ERR_OPT_INVALID;
427  return ((void *)0);
428  }
429 #endif
430 
431 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
432  if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
433  *p_err = OS_ERR_OBJ_TYPE;
434  return ((void *)0);
435  }
436 #endif
437 
438  if (p_ts != (CPU_TS *)0) {
439  *p_ts = (CPU_TS )0; /* Initialize the returned timestamp */
440  }
441 
443  p_void = OS_MsgQGet(&p_q->MsgQ, /* Any message waiting in the message queue? */
444  p_msg_size,
445  p_ts,
446  p_err);
447  if (*p_err == OS_ERR_NONE) {
449  return (p_void); /* Yes, Return message received */
450  }
451 
452  if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */
454  *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */
455  return ((void *)0);
456  } else {
457  if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */
459  *p_err = OS_ERR_SCHED_LOCKED;
460  return ((void *)0);
461  }
462  }
463 
464  OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
465  OS_Pend(&pend_data, /* Block task pending on Message Queue */
466  (OS_PEND_OBJ *)((void *)p_q),
468  timeout);
470 
471  OSSched(); /* Find the next highest priority task ready to run */
472 
474  switch (OSTCBCurPtr->PendStatus) {
475  case OS_STATUS_PEND_OK: /* Extract message from TCB (Put there by Post) */
476  p_void = OSTCBCurPtr->MsgPtr;
477  *p_msg_size = OSTCBCurPtr->MsgSize;
478  if (p_ts != (CPU_TS *)0) {
479  *p_ts = OSTCBCurPtr->TS;
480  }
481  *p_err = OS_ERR_NONE;
482  break;
483 
484  case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */
485  p_void = (void *)0;
486  *p_msg_size = (OS_MSG_SIZE)0;
487  if (p_ts != (CPU_TS *)0) {
488  *p_ts = OSTCBCurPtr->TS;
489  }
490  *p_err = OS_ERR_PEND_ABORT;
491  break;
492 
493  case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get event within TO */
494  p_void = (void *)0;
495  *p_msg_size = (OS_MSG_SIZE)0;
496  if (p_ts != (CPU_TS *)0) {
497  *p_ts = (CPU_TS )0;
498  }
499  *p_err = OS_ERR_TIMEOUT;
500  break;
501 
502  case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */
503  p_void = (void *)0;
504  *p_msg_size = (OS_MSG_SIZE)0;
505  if (p_ts != (CPU_TS *)0) {
506  *p_ts = OSTCBCurPtr->TS;
507  }
508  *p_err = OS_ERR_OBJ_DEL;
509  break;
510 
511  default:
512  p_void = (void *)0;
513  *p_msg_size = (OS_MSG_SIZE)0;
514  *p_err = OS_ERR_STATUS_INVALID;
515  break;
516  }
518  return (p_void);
519 }
520 
521 
522 /*$PAGE*/
523 /*
524 ************************************************************************************************************************
525 * ABORT WAITING ON A MESSAGE QUEUE
526 *
527 * Description: This function aborts & readies any tasks currently waiting on a queue. This function should be used to
528 * fault-abort the wait on the queue, rather than to normally signal the queue via OSQPost().
529 *
530 * Arguments : p_q is a pointer to the message queue
531 *
532 * opt determines the type of ABORT performed:
533 *
534 * OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the queue
535 * OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the queue
536 * OS_OPT_POST_NO_SCHED Do not call the scheduler
537 *
538 * p_err is a pointer to a variable that will contain an error code returned by this function.
539 *
540 * OS_ERR_NONE At least one task waiting on the queue was readied and
541 * informed of the aborted wait; check return value for the
542 * number of tasks whose wait on the queue was aborted.
543 * OS_ERR_OPT_INVALID if you specified an invalid option
544 * OS_ERR_OBJ_PTR_NULL if you pass a NULL pointer for 'p_q'
545 * OS_ERR_OBJ_TYPE if the message queue was not created
546 * OS_ERR_PEND_ABORT_ISR If this function was called from an ISR
547 * OS_ERR_PEND_ABORT_NONE No task were pending
548 *
549 * Returns : == 0 if no tasks were waiting on the queue, or upon error.
550 * > 0 if one or more tasks waiting on the queue are now readied and informed.
551 ************************************************************************************************************************
552 */
553 
554 #if OS_CFG_Q_PEND_ABORT_EN > 0u
555 OS_OBJ_QTY OSQPendAbort (OS_Q *p_q,
556  OS_OPT opt,
557  OS_ERR *p_err)
558 {
559  OS_PEND_LIST *p_pend_list;
560  OS_TCB *p_tcb;
561  CPU_TS ts;
562  OS_OBJ_QTY nbr_tasks;
563  CPU_SR_ALLOC();
564 
565 
566 
567 #ifdef OS_SAFETY_CRITICAL
568  if (p_err == (OS_ERR *)0) {
569  OS_SAFETY_CRITICAL_EXCEPTION();
570  return ((OS_OBJ_QTY)0u);
571  }
572 #endif
573 
574 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
575  if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to Pend Abort from an ISR */
576  *p_err = OS_ERR_PEND_ABORT_ISR;
577  return ((OS_OBJ_QTY)0u);
578  }
579 #endif
580 
581 #if OS_CFG_ARG_CHK_EN > 0u
582  if (p_q == (OS_Q *)0) { /* Validate 'p_q' */
583  *p_err = OS_ERR_OBJ_PTR_NULL;
584  return ((OS_OBJ_QTY)0u);
585  }
586  switch (opt) { /* Validate 'opt' */
587  case OS_OPT_PEND_ABORT_1:
591  break;
592 
593  default:
594  *p_err = OS_ERR_OPT_INVALID;
595  return ((OS_OBJ_QTY)0u);
596  }
597 #endif
598 
599 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
600  if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure queue was created */
601  *p_err = OS_ERR_OBJ_TYPE;
602  return ((OS_OBJ_QTY)0u);
603  }
604 #endif
605 
607  p_pend_list = &p_q->PendList;
608  if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0u) { /* Any task waiting on queue? */
609  CPU_CRITICAL_EXIT(); /* No */
610  *p_err = OS_ERR_PEND_ABORT_NONE;
611  return ((OS_OBJ_QTY)0u);
612  }
613 
615  nbr_tasks = 0u;
616  ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
617  while (p_pend_list->NbrEntries > (OS_OBJ_QTY)0u) {
618  p_tcb = p_pend_list->HeadPtr->TCBPtr;
619  OS_PendAbort((OS_PEND_OBJ *)((void *)p_q),
620  p_tcb,
621  ts);
622  nbr_tasks++;
623  if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */
624  break; /* No */
625  }
626  }
628 
629  if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0u) {
630  OSSched(); /* Run the scheduler */
631  }
632 
633  *p_err = OS_ERR_NONE;
634  return (nbr_tasks);
635 }
636 #endif
637 
638 /*$PAGE*/
639 /*
640 ************************************************************************************************************************
641 * POST MESSAGE TO A QUEUE
642 *
643 * Description: This function sends a message to a queue. With the 'opt' argument, you can specify whether the message
644 * is broadcast to all waiting tasks and/or whether you post the message to the front of the queue (LIFO)
645 * or normally (FIFO) at the end of the queue.
646 *
647 * Arguments : p_q is a pointer to a message queue that must have been created by OSQCreate().
648 *
649 * p_void is a pointer to the message to send.
650 *
651 * msg_size specifies the size of the message (in bytes)
652 *
653 * opt determines the type of POST performed:
654 *
655 * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the queue. This option
656 * can be added to either OS_OPT_POST_FIFO or OS_OPT_POST_LIFO
657 * OS_OPT_POST_FIFO POST message to end of queue (FIFO) and wake up a single
658 * waiting task.
659 * OS_OPT_POST_LIFO POST message to the front of the queue (LIFO) and wake up
660 * a single waiting task.
661 * OS_OPT_POST_NO_SCHED Do not call the scheduler
662 *
663 * Note(s): 1) OS_OPT_POST_NO_SCHED can be added (or OR'd) with one of the other options.
664 * 2) OS_OPT_POST_ALL can be added (or OR'd) with one of the other options.
665 * 3) Possible combination of options are:
666 *
667 * OS_OPT_POST_FIFO
668 * OS_OPT_POST_LIFO
669 * OS_OPT_POST_FIFO + OS_OPT_POST_ALL
670 * OS_OPT_POST_LIFO + OS_OPT_POST_ALL
671 * OS_OPT_POST_FIFO + OS_OPT_POST_NO_SCHED
672 * OS_OPT_POST_LIFO + OS_OPT_POST_NO_SCHED
673 * OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED
674 * OS_OPT_POST_LIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED
675 *
676 * p_err is a pointer to a variable that will contain an error code returned by this function.
677 *
678 * OS_ERR_NONE The call was successful and the message was sent
679 * OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs to use to place the message into
680 * OS_ERR_OBJ_PTR_NULL If 'p_q' is a NULL pointer
681 * OS_ERR_OBJ_TYPE If the message queue was not initialized
682 * OS_ERR_Q_MAX If the queue is full
683 *
684 * Returns : None
685 ************************************************************************************************************************
686 */
687 
688 void OSQPost (OS_Q *p_q,
689  void *p_void,
690  OS_MSG_SIZE msg_size,
691  OS_OPT opt,
692  OS_ERR *p_err)
693 {
694  CPU_TS ts;
695 
696 
697 
698 #ifdef OS_SAFETY_CRITICAL
699  if (p_err == (OS_ERR *)0) {
700  OS_SAFETY_CRITICAL_EXCEPTION();
701  return;
702  }
703 #endif
704 
705 #if OS_CFG_ARG_CHK_EN > 0u
706  if (p_q == (OS_Q *)0) { /* Validate 'p_q' */
707  *p_err = OS_ERR_OBJ_PTR_NULL;
708  return;
709  }
710  switch (opt) { /* Validate 'opt' */
711  case OS_OPT_POST_FIFO:
712  case OS_OPT_POST_LIFO:
715  case OS_OPT_POST_FIFO | OS_OPT_POST_NO_SCHED:
716  case OS_OPT_POST_LIFO | OS_OPT_POST_NO_SCHED:
717  case OS_OPT_POST_FIFO | OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED:
718  case OS_OPT_POST_LIFO | OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED:
719  break;
720 
721  default:
722  *p_err = OS_ERR_OPT_INVALID;
723  return;
724  }
725 #endif
726 
727 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
728  if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */
729  *p_err = OS_ERR_OBJ_TYPE;
730  return;
731  }
732 #endif
733 
734  ts = OS_TS_GET(); /* Get timestamp */
735 
736 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
737  if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
738  OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_Q, /* Post to ISR queue */
739  (void *)p_q,
740  (void *)p_void,
741  (OS_MSG_SIZE)msg_size,
742  (OS_FLAGS )0,
743  (OS_OPT )opt,
744  (CPU_TS )ts,
745  (OS_ERR *)p_err);
746  return;
747  }
748 #endif
749 
750  OS_QPost(p_q,
751  p_void,
752  msg_size,
753  opt,
754  ts,
755  p_err);
756 }
757 
758 /*$PAGE*/
759 /*
760 ************************************************************************************************************************
761 * CLEAR THE CONTENTS OF A MESSAGE QUEUE
762 *
763 * Description: This function is called by OSQDel() to clear the contents of a message queue
764 *
765 
766 * Argument(s): p_q is a pointer to the queue to clear
767 * ---
768 *
769 * Returns : none
770 *
771 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
772 ************************************************************************************************************************
773 */
774 
775 void OS_QClr (OS_Q *p_q)
776 {
777  (void)OS_MsgQFreeAll(&p_q->MsgQ); /* Return all OS_MSGs to the free list */
778  p_q->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */
779  p_q->NamePtr = (CPU_CHAR *)((void *)"?Q");
780  OS_MsgQInit(&p_q->MsgQ, /* Initialize the list of OS_MSGs */
781  0u);
782  OS_PendListInit(&p_q->PendList); /* Initialize the waiting list */
783 }
784 
785 /*$PAGE*/
786 /*
787 ************************************************************************************************************************
788 * ADD/REMOVE MESSAGE QUEUE TO/FROM DEBUG LIST
789 *
790 * Description: These functions are called by uC/OS-III to add or remove a message queue to/from a message queue debug
791 * list.
792 *
793 * Arguments : p_q is a pointer to the message queue to add/remove
794 *
795 * Returns : none
796 *
797 * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
798 ************************************************************************************************************************
799 */
800 
801 
802 #if OS_CFG_DBG_EN > 0u
803 void OS_QDbgListAdd (OS_Q *p_q)
804 {
805  p_q->DbgNamePtr = (CPU_CHAR *)((void *)" ");
806  p_q->DbgPrevPtr = (OS_Q *)0;
807  if (OSQDbgListPtr == (OS_Q *)0) {
808  p_q->DbgNextPtr = (OS_Q *)0;
809  } else {
810  p_q->DbgNextPtr = OSQDbgListPtr;
811  OSQDbgListPtr->DbgPrevPtr = p_q;
812  }
813  OSQDbgListPtr = p_q;
814 }
815 
816 
817 
818 void OS_QDbgListRemove (OS_Q *p_q)
819 {
820  OS_Q *p_q_next;
821  OS_Q *p_q_prev;
822 
823 
824  p_q_prev = p_q->DbgPrevPtr;
825  p_q_next = p_q->DbgNextPtr;
826 
827  if (p_q_prev == (OS_Q *)0) {
828  OSQDbgListPtr = p_q_next;
829  if (p_q_next != (OS_Q *)0) {
830  p_q_next->DbgPrevPtr = (OS_Q *)0;
831  }
832  p_q->DbgNextPtr = (OS_Q *)0;
833 
834  } else if (p_q_next == (OS_Q *)0) {
835  p_q_prev->DbgNextPtr = (OS_Q *)0;
836  p_q->DbgPrevPtr = (OS_Q *)0;
837 
838  } else {
839  p_q_prev->DbgNextPtr = p_q_next;
840  p_q_next->DbgPrevPtr = p_q_prev;
841  p_q->DbgNextPtr = (OS_Q *)0;
842  p_q->DbgPrevPtr = (OS_Q *)0;
843  }
844 }
845 #endif
846 
847 /*$PAGE*/
848 /*
849 ************************************************************************************************************************
850 * MESSAGE QUEUE INITIALIZATION
851 *
852 * Description: This function is called by OSInit() to initialize the message queue management.
853 *
854 
855 * Arguments : p_err is a pointer to a variable that will receive an error code.
856 *
857 * OS_ERR_NONE the call was successful
858 *
859 * Returns : none
860 *
861 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
862 ************************************************************************************************************************
863 */
864 
865 void OS_QInit (OS_ERR *p_err)
866 {
867 #ifdef OS_SAFETY_CRITICAL
868  if (p_err == (OS_ERR *)0) {
869  OS_SAFETY_CRITICAL_EXCEPTION();
870  return;
871  }
872 #endif
873 
874 #if OS_CFG_DBG_EN > 0u
875  OSQDbgListPtr = (OS_Q *)0;
876 #endif
877 
878  OSQQty = (OS_OBJ_QTY)0;
879  *p_err = OS_ERR_NONE;
880 }
881 
882 /*$PAGE*/
883 /*
884 ************************************************************************************************************************
885 * POST MESSAGE TO A QUEUE
886 *
887 * Description: This function sends a message to a queue. With the 'opt' argument, you can specify whether the message
888 * is broadcast to all waiting tasks and/or whether you post the message to the front of the queue (LIFO)
889 * or normally (FIFO) at the end of the queue.
890 *
891 * Arguments : p_q is a pointer to a message queue that must have been created by OSQCreate().
892 *
893 * p_void is a pointer to the message to send.
894 *
895 * msg_size specifies the size of the message (in bytes)
896 *
897 * opt determines the type of POST performed:
898 *
899 * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the queue
900 *
901 * OS_OPT_POST_FIFO POST as FIFO and wake up single waiting task
902 * OS_OPT_POST_LIFO POST as LIFO and wake up single waiting task
903 *
904 * OS_OPT_POST_NO_SCHED Do not call the scheduler
905 *
906 * ts is the timestamp of the post
907 *
908 * p_err is a pointer to a variable that will contain an error code returned by this function.
909 *
910 * OS_ERR_NONE The call was successful and the message was sent
911 * OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs to use to place the message into
912 * OS_ERR_OBJ_PTR_NULL If 'p_q' is a NULL pointer
913 * OS_ERR_OBJ_TYPE If the message queue was not initialized
914 * OS_ERR_Q_MAX If the queue is full
915 *
916 * Returns : None
917 *
918 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
919 ************************************************************************************************************************
920 */
921 
922 void OS_QPost (OS_Q *p_q,
923  void *p_void,
924  OS_MSG_SIZE msg_size,
925  OS_OPT opt,
926  CPU_TS ts,
927  OS_ERR *p_err)
928 {
929  OS_OBJ_QTY cnt;
930  OS_OPT post_type;
931  OS_PEND_LIST *p_pend_list;
932  OS_PEND_DATA *p_pend_data;
933  OS_PEND_DATA *p_pend_data_next;
934  OS_TCB *p_tcb;
935  CPU_SR_ALLOC();
936 
937 
938 
940  p_pend_list = &p_q->PendList;
941  if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { /* Any task waiting on message queue? */
942  if ((opt & OS_OPT_POST_LIFO) == (OS_OPT)0) { /* Determine whether we post FIFO or LIFO */
943  post_type = OS_OPT_POST_FIFO;
944  } else {
945  post_type = OS_OPT_POST_LIFO;
946  }
947  OS_MsgQPut(&p_q->MsgQ, /* Place message in the message queue */
948  p_void,
949  msg_size,
950  post_type,
951  ts,
952  p_err);
954  return;
955  }
956 
957  if ((opt & OS_OPT_POST_ALL) != (OS_OPT)0) { /* Post message to all tasks waiting? */
958  cnt = p_pend_list->NbrEntries; /* Yes */
959  } else {
960  cnt = (OS_OBJ_QTY)1; /* No */
961  }
962  p_pend_data = p_pend_list->HeadPtr;
963  while (cnt > 0u) {
964  p_tcb = p_pend_data->TCBPtr;
965  p_pend_data_next = p_pend_data->NextPtr;
966  OS_Post((OS_PEND_OBJ *)((void *)p_q),
967  p_tcb,
968  p_void,
969  msg_size,
970  ts);
971  p_pend_data = p_pend_data_next;
972  cnt--;
973  }
975  if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
976  OSSched(); /* Run the scheduler */
977  }
978  *p_err = OS_ERR_NONE;
979 }
980 
981 #endif