os_q.c
上传用户:yj_qqy
上传日期:2017-01-28
资源大小:2911k
文件大小:41k
源码类别:

uCOS

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                        MESSAGE QUEUE MANAGEMENT
  6. *
  7. *                              (c) Copyright 1992-2009, Micrium, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File    : OS_Q.C
  11. * By      : Jean J. Labrosse
  12. * Version : V2.88
  13. *
  14. * LICENSING TERMS:
  15. * ---------------
  16. *   uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.  
  17. * If you plan on using  uC/OS-II  in a commercial product you need to contact Micri祄 to properly license 
  18. * its use in your product. We provide ALL the source code for your convenience and to help you experience 
  19. * uC/OS-II.   The fact that the  source is provided does  NOT  mean that you can use it without  paying a 
  20. * licensing fee.
  21. *********************************************************************************************************
  22. */
  23. #ifndef  OS_MASTER_FILE
  24. #include <ucos_ii.h>
  25. #endif
  26. #if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
  27. /*
  28. *********************************************************************************************************
  29. *                                      ACCEPT MESSAGE FROM QUEUE
  30. *
  31. * Description: This function checks the queue to see if a message is available.  Unlike OSQPend(),
  32. *              OSQAccept() does not suspend the calling task if a message is not available.
  33. *
  34. * Arguments  : pevent        is a pointer to the event control block
  35. *
  36. *              perr          is a pointer to where an error message will be deposited.  Possible error
  37. *                            messages are:
  38. *
  39. *                            OS_ERR_NONE         The call was successful and your task received a
  40. *                                                message.
  41. *                            OS_ERR_EVENT_TYPE   You didn't pass a pointer to a queue
  42. *                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  43. *                            OS_ERR_Q_EMPTY      The queue did not contain any messages
  44. *
  45. * Returns    : != (void *)0  is the message in the queue if one is available.  The message is removed
  46. *                            from the so the next time OSQAccept() is called, the queue will contain
  47. *                            one less entry.
  48. *              == (void *)0  if you received a NULL pointer message
  49. *                            if the queue is empty or,
  50. *                            if 'pevent' is a NULL pointer or,
  51. *                            if you passed an invalid event type
  52. *
  53. * Note(s)    : As of V2.60, you can now pass NULL pointers through queues.  Because of this, the argument
  54. *              'perr' has been added to the API to tell you about the outcome of the call.
  55. *********************************************************************************************************
  56. */
  57. #if OS_Q_ACCEPT_EN > 0
  58. void  *OSQAccept (OS_EVENT  *pevent, 
  59.                   INT8U     *perr)
  60. {
  61.     void      *pmsg;
  62.     OS_Q      *pq;
  63. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  64.     OS_CPU_SR  cpu_sr = 0;
  65. #endif
  66. #if OS_ARG_CHK_EN > 0
  67.     if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
  68.         return ((void *)0);
  69.     }
  70.     if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
  71.         *perr = OS_ERR_PEVENT_NULL;
  72.         return ((void *)0);
  73.     }
  74. #endif
  75.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
  76.         *perr = OS_ERR_EVENT_TYPE;
  77.         return ((void *)0);
  78.     }
  79.     OS_ENTER_CRITICAL();
  80.     pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
  81.     if (pq->OSQEntries > 0) {                    /* See if any messages in the queue                   */
  82.         pmsg = *pq->OSQOut++;                    /* Yes, extract oldest message from the queue         */
  83.         pq->OSQEntries--;                        /* Update the number of entries in the queue          */
  84.         if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
  85.             pq->OSQOut = pq->OSQStart;
  86.         }
  87.         *perr = OS_ERR_NONE;
  88.     } else {
  89.         *perr = OS_ERR_Q_EMPTY;
  90.         pmsg  = (void *)0;                       /* Queue is empty                                     */
  91.     }
  92.     OS_EXIT_CRITICAL();
  93.     return (pmsg);                               /* Return message received (or NULL)                  */
  94. }
  95. #endif
  96. /*$PAGE*/
  97. /*
  98. *********************************************************************************************************
  99. *                                        CREATE A MESSAGE QUEUE
  100. *
  101. * Description: This function creates a message queue if free event control blocks are available.
  102. *
  103. * Arguments  : start         is a pointer to the base address of the message queue storage area.  The
  104. *                            storage area MUST be declared as an array of pointers to 'void' as follows
  105. *
  106. *                            void *MessageStorage[size]
  107. *
  108. *              size          is the number of elements in the storage area
  109. *
  110. * Returns    : != (OS_EVENT *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  111. *                                created queue
  112. *              == (OS_EVENT *)0  if no event control blocks were available or an error was detected
  113. *********************************************************************************************************
  114. */
  115. OS_EVENT  *OSQCreate (void    **start,
  116.                       INT16U    size)
  117. {
  118.     OS_EVENT  *pevent;
  119.     OS_Q      *pq;
  120. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  121.     OS_CPU_SR  cpu_sr = 0;
  122. #endif
  123.     if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
  124.         return ((OS_EVENT *)0);                  /* ... can't CREATE from an ISR                       */
  125.     }
  126.     OS_ENTER_CRITICAL();
  127.     pevent = OSEventFreeList;                    /* Get next free event control block                  */
  128.     if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
  129.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  130.     }
  131.     OS_EXIT_CRITICAL();
  132.     if (pevent != (OS_EVENT *)0) {               /* See if we have an event control block              */
  133.         OS_ENTER_CRITICAL();
  134.         pq = OSQFreeList;                        /* Get a free queue control block                     */
  135.         if (pq != (OS_Q *)0) {                   /* Were we able to get a queue control block ?        */
  136.             OSQFreeList            = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
  137.             OS_EXIT_CRITICAL();
  138.             pq->OSQStart           = start;               /*      Initialize the queue                 */
  139.             pq->OSQEnd             = &start[size];
  140.             pq->OSQIn              = start;
  141.             pq->OSQOut             = start;
  142.             pq->OSQSize            = size;
  143.             pq->OSQEntries         = 0;
  144.             pevent->OSEventType    = OS_EVENT_TYPE_Q;
  145.             pevent->OSEventCnt     = 0;
  146.             pevent->OSEventPtr     = pq;
  147. #if OS_EVENT_NAME_EN > 0
  148.             pevent->OSEventName    = "?";                 /* Unknown name                             */
  149. #endif
  150.             OS_EventWaitListInit(pevent);                 /*      Initalize the wait list              */
  151.         } else {
  152.             pevent->OSEventPtr = (void *)OSEventFreeList; /* No,  Return event control block on error  */
  153.             OSEventFreeList    = pevent;
  154.             OS_EXIT_CRITICAL();
  155.             pevent = (OS_EVENT *)0;
  156.         }
  157.     }
  158.     return (pevent);
  159. }
  160. /*$PAGE*/
  161. /*
  162. *********************************************************************************************************
  163. *                                        DELETE A MESSAGE QUEUE
  164. *
  165. * Description: This function deletes a message queue and readies all tasks pending on the queue.
  166. *
  167. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  168. *                            queue.
  169. *
  170. *              opt           determines delete options as follows:
  171. *                            opt == OS_DEL_NO_PEND   Delete the queue ONLY if no task pending
  172. *                            opt == OS_DEL_ALWAYS    Deletes the queue even if tasks are waiting.
  173. *                                                    In this case, all the tasks pending will be readied.
  174. *
  175. *              perr          is a pointer to an error code that can contain one of the following values:
  176. *                            OS_ERR_NONE             The call was successful and the queue was deleted
  177. *                            OS_ERR_DEL_ISR          If you tried to delete the queue from an ISR
  178. *                            OS_ERR_INVALID_OPT      An invalid option was specified
  179. *                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the queue
  180. *                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a queue
  181. *                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
  182. *
  183. * Returns    : pevent        upon error
  184. *              (OS_EVENT *)0 if the queue was successfully deleted.
  185. *
  186. * Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
  187. *                 the queue MUST check the return code of OSQPend().
  188. *              2) OSQAccept() callers will not know that the intended queue has been deleted unless
  189. *                 they check 'pevent' to see that it's a NULL pointer.
  190. *              3) This call can potentially disable interrupts for a long time.  The interrupt disable
  191. *                 time is directly proportional to the number of tasks waiting on the queue.
  192. *              4) Because ALL tasks pending on the queue will be readied, you MUST be careful in
  193. *                 applications where the queue is used for mutual exclusion because the resource(s)
  194. *                 will no longer be guarded by the queue.
  195. *              5) If the storage for the message queue was allocated dynamically (i.e. using a malloc()
  196. *                 type call) then your application MUST release the memory storage by call the counterpart
  197. *                 call of the dynamic allocation scheme used.  If the queue storage was created statically
  198. *                 then, the storage can be reused.
  199. *********************************************************************************************************
  200. */
  201. #if OS_Q_DEL_EN > 0
  202. OS_EVENT  *OSQDel (OS_EVENT  *pevent, 
  203.                    INT8U      opt, 
  204.                    INT8U     *perr)
  205. {
  206.     BOOLEAN    tasks_waiting;
  207.     OS_EVENT  *pevent_return;
  208.     OS_Q      *pq;
  209. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  210.     OS_CPU_SR  cpu_sr = 0;
  211. #endif
  212. #if OS_ARG_CHK_EN > 0
  213.     if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */
  214.         return (pevent);
  215.     }
  216.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  217.         *perr = OS_ERR_PEVENT_NULL;
  218.         return (pevent);
  219.     }
  220. #endif
  221.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
  222.         *perr = OS_ERR_EVENT_TYPE;
  223.         return (pevent);
  224.     }
  225.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  226.         *perr = OS_ERR_DEL_ISR;                            /* ... can't DELETE from an ISR             */
  227.         return (pevent);
  228.     }
  229.     OS_ENTER_CRITICAL();
  230.     if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on queue        */
  231.         tasks_waiting = OS_TRUE;                           /* Yes                                      */
  232.     } else {
  233.         tasks_waiting = OS_FALSE;                          /* No                                       */
  234.     }
  235.     switch (opt) {
  236.         case OS_DEL_NO_PEND:                               /* Delete queue only if no task waiting     */
  237.              if (tasks_waiting == OS_FALSE) {
  238. #if OS_EVENT_NAME_EN > 0
  239.                  pevent->OSEventName    = "?";                         /* Unknown name                 */
  240. #endif
  241.                  pq                     = (OS_Q *)pevent->OSEventPtr;  /* Return OS_Q to free list     */
  242.                  pq->OSQPtr             = OSQFreeList;
  243.                  OSQFreeList            = pq;
  244.                  pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
  245.                  pevent->OSEventPtr     = OSEventFreeList; /* Return Event Control Block to free list  */
  246.                  pevent->OSEventCnt     = 0;
  247.                  OSEventFreeList        = pevent;          /* Get next free event control block        */
  248.                  OS_EXIT_CRITICAL();
  249.                  *perr                  = OS_ERR_NONE;
  250.                  pevent_return          = (OS_EVENT *)0;   /* Queue has been deleted                   */
  251.              } else {
  252.                  OS_EXIT_CRITICAL();
  253.                  *perr                  = OS_ERR_TASK_WAITING;
  254.                  pevent_return          = pevent;
  255.              }
  256.              break;
  257.         case OS_DEL_ALWAYS:                                /* Always delete the queue                  */
  258.              while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for queue        */
  259.                  (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_OK);
  260.              }
  261. #if OS_EVENT_NAME_EN > 0
  262.              pevent->OSEventName    = "?";                          /* Unknown name                    */
  263. #endif
  264.              pq                     = (OS_Q *)pevent->OSEventPtr;   /* Return OS_Q to free list        */
  265.              pq->OSQPtr             = OSQFreeList;
  266.              OSQFreeList            = pq;
  267.              pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
  268.              pevent->OSEventPtr     = OSEventFreeList;     /* Return Event Control Block to free list  */
  269.              pevent->OSEventCnt     = 0;
  270.              OSEventFreeList        = pevent;              /* Get next free event control block        */
  271.              OS_EXIT_CRITICAL();
  272.              if (tasks_waiting == OS_TRUE) {               /* Reschedule only if task(s) were waiting  */
  273.                  OS_Sched();                               /* Find highest priority task ready to run  */
  274.              }
  275.              *perr                  = OS_ERR_NONE;
  276.              pevent_return          = (OS_EVENT *)0;       /* Queue has been deleted                   */
  277.              break;
  278.         default:
  279.              OS_EXIT_CRITICAL();
  280.              *perr                  = OS_ERR_INVALID_OPT;
  281.              pevent_return          = pevent;
  282.              break;
  283.     }
  284.     return (pevent_return);
  285. }
  286. #endif
  287. /*$PAGE*/
  288. /*
  289. *********************************************************************************************************
  290. *                                             FLUSH QUEUE
  291. *
  292. * Description : This function is used to flush the contents of the message queue.
  293. *
  294. * Arguments   : none
  295. *
  296. * Returns     : OS_ERR_NONE         upon success
  297. *               OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a queue
  298. *               OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  299. *
  300. * WARNING     : You should use this function with great care because, when to flush the queue, you LOOSE
  301. *               the references to what the queue entries are pointing to and thus, you could cause
  302. *               'memory leaks'.  In other words, the data you are pointing to that's being referenced
  303. *               by the queue entries should, most likely, need to be de-allocated (i.e. freed).
  304. *********************************************************************************************************
  305. */
  306. #if OS_Q_FLUSH_EN > 0
  307. INT8U  OSQFlush (OS_EVENT *pevent)
  308. {
  309.     OS_Q      *pq;
  310. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  311.     OS_CPU_SR  cpu_sr = 0;
  312. #endif
  313. #if OS_ARG_CHK_EN > 0
  314.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  315.         return (OS_ERR_PEVENT_NULL);
  316.     }
  317.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  318.         return (OS_ERR_EVENT_TYPE);
  319.     }
  320. #endif
  321.     OS_ENTER_CRITICAL();
  322.     pq             = (OS_Q *)pevent->OSEventPtr;      /* Point to queue storage structure              */
  323.     pq->OSQIn      = pq->OSQStart;
  324.     pq->OSQOut     = pq->OSQStart;
  325.     pq->OSQEntries = 0;
  326.     OS_EXIT_CRITICAL();
  327.     return (OS_ERR_NONE);
  328. }
  329. #endif
  330. /*$PAGE*/
  331. /*
  332. *********************************************************************************************************
  333. *                                     PEND ON A QUEUE FOR A MESSAGE
  334. *
  335. * Description: This function waits for a message to be sent to a queue
  336. *
  337. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  338. *
  339. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  340. *                            wait for a message to arrive at the queue up to the amount of time
  341. *                            specified by this argument.  If you specify 0, however, your task will wait
  342. *                            forever at the specified queue or, until a message arrives.
  343. *
  344. *              perr          is a pointer to where an error message will be deposited.  Possible error
  345. *                            messages are:
  346. *
  347. *                            OS_ERR_NONE         The call was successful and your task received a
  348. *                                                message.
  349. *                            OS_ERR_TIMEOUT      A message was not received within the specified 'timeout'.
  350. *                            OS_ERR_PEND_ABORT   The wait on the queue was aborted.
  351. *                            OS_ERR_EVENT_TYPE   You didn't pass a pointer to a queue
  352. *                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  353. *                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
  354. *                                                would lead to a suspension.
  355. *                            OS_ERR_PEND_LOCKED  If you called this function with the scheduler is locked
  356. *
  357. * Returns    : != (void *)0  is a pointer to the message received
  358. *              == (void *)0  if you received a NULL pointer message or,
  359. *                            if no message was received or,
  360. *                            if 'pevent' is a NULL pointer or,
  361. *                            if you didn't pass a pointer to a queue.
  362. *
  363. * Note(s)    : As of V2.60, this function allows you to receive NULL pointer messages.
  364. *********************************************************************************************************
  365. */
  366. void  *OSQPend (OS_EVENT  *pevent, 
  367.                 INT32U     timeout, 
  368.                 INT8U     *perr)
  369. {
  370.     void      *pmsg;
  371.     OS_Q      *pq;
  372. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  373.     OS_CPU_SR  cpu_sr = 0;
  374. #endif
  375. #if OS_ARG_CHK_EN > 0
  376.     if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
  377.         return ((void *)0);
  378.     }
  379.     if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
  380.         *perr = OS_ERR_PEVENT_NULL;
  381.         return ((void *)0);
  382.     }
  383. #endif
  384.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
  385.         *perr = OS_ERR_EVENT_TYPE;
  386.         return ((void *)0);
  387.     }
  388.     if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
  389.         *perr = OS_ERR_PEND_ISR;                 /* ... can't PEND from an ISR                         */
  390.         return ((void *)0);
  391.     }
  392.     if (OSLockNesting > 0) {                     /* See if called with scheduler locked ...            */
  393.         *perr = OS_ERR_PEND_LOCKED;              /* ... can't PEND when locked                         */
  394.         return ((void *)0);
  395.     }
  396.     OS_ENTER_CRITICAL();
  397.     pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
  398.     if (pq->OSQEntries > 0) {                    /* See if any messages in the queue                   */
  399.         pmsg = *pq->OSQOut++;                    /* Yes, extract oldest message from the queue         */
  400.         pq->OSQEntries--;                        /* Update the number of entries in the queue          */
  401.         if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
  402.             pq->OSQOut = pq->OSQStart;
  403.         }
  404.         OS_EXIT_CRITICAL();
  405.         *perr = OS_ERR_NONE;
  406.         return (pmsg);                           /* Return message received                            */
  407.     }
  408.     OSTCBCur->OSTCBStat     |= OS_STAT_Q;        /* Task will have to pend for a message to be posted  */
  409.     OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
  410.     OSTCBCur->OSTCBDly       = timeout;          /* Load timeout into TCB                              */
  411.     OS_EventTaskWait(pevent);                    /* Suspend task until event or timeout occurs         */
  412.     OS_EXIT_CRITICAL();
  413.     OS_Sched();                                  /* Find next highest priority task ready to run       */
  414.     OS_ENTER_CRITICAL();
  415.     switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
  416.         case OS_STAT_PEND_OK:                         /* Extract message from TCB (Put there by QPost) */
  417.              pmsg =  OSTCBCur->OSTCBMsg;
  418.             *perr =  OS_ERR_NONE;
  419.              break;
  420.         case OS_STAT_PEND_ABORT:
  421.              pmsg = (void *)0;
  422.             *perr =  OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */
  423.              break;
  424.         case OS_STAT_PEND_TO:
  425.         default:
  426.              OS_EventTaskRemove(OSTCBCur, pevent);
  427.              pmsg = (void *)0;
  428.             *perr =  OS_ERR_TIMEOUT;                  /* Indicate that we didn't get event within TO   */
  429.              break;
  430.     }
  431.     OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */
  432.     OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */
  433.     OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */
  434. #if (OS_EVENT_MULTI_EN > 0)
  435.     OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  436. #endif
  437.     OSTCBCur->OSTCBMsg           = (void      *)0;    /* Clear  received message                       */
  438.     OS_EXIT_CRITICAL();
  439.     return (pmsg);                                    /* Return received message                       */
  440. }
  441. /*$PAGE*/
  442. /*
  443. *********************************************************************************************************
  444. *                                      ABORT WAITING ON A MESSAGE QUEUE
  445. *
  446. * Description: This function aborts & readies any tasks currently waiting on a queue.  This function 
  447. *              should be used to fault-abort the wait on the queue, rather than to normally signal
  448. *              the queue via OSQPost(), OSQPostFront() or OSQPostOpt().
  449. *
  450. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue.
  451. *
  452. *              opt           determines the type of ABORT performed:
  453. *                            OS_PEND_OPT_NONE         ABORT wait for a single task (HPT) waiting on the
  454. *                                                     queue
  455. *                            OS_PEND_OPT_BROADCAST    ABORT wait for ALL tasks that are  waiting on the
  456. *                                                     queue
  457. *
  458. *              perr          is a pointer to where an error message will be deposited.  Possible error
  459. *                            messages are:
  460. *
  461. *                            OS_ERR_NONE         No tasks were     waiting on the queue.
  462. *                            OS_ERR_PEND_ABORT   At least one task waiting on the queue was readied
  463. *                                                and informed of the aborted wait; check return value 
  464. *                                                for the number of tasks whose wait on the queue 
  465. *                                                was aborted.
  466. *                            OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a queue.
  467. *                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
  468. *
  469. * Returns    : == 0          if no tasks were waiting on the queue, or upon error.
  470. *              >  0          if one or more tasks waiting on the queue are now readied and informed.
  471. *********************************************************************************************************
  472. */
  473. #if OS_Q_PEND_ABORT_EN > 0
  474. INT8U  OSQPendAbort (OS_EVENT  *pevent, 
  475.                      INT8U      opt, 
  476.                      INT8U     *perr)
  477. {
  478.     INT8U      nbr_tasks;
  479. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  480.     OS_CPU_SR  cpu_sr = 0;
  481. #endif
  482. #if OS_ARG_CHK_EN > 0
  483.     if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */
  484.         return (0);
  485.     }
  486.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  487.         *perr = OS_ERR_PEVENT_NULL;
  488.         return (0);
  489.     }
  490. #endif
  491.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
  492.         *perr = OS_ERR_EVENT_TYPE;
  493.         return (0);
  494.     }
  495.     OS_ENTER_CRITICAL();
  496.     if (pevent->OSEventGrp != 0) {                         /* See if any task waiting on queue?        */
  497.         nbr_tasks = 0;
  498.         switch (opt) {
  499.             case OS_PEND_OPT_BROADCAST:                    /* Do we need to abort ALL waiting tasks?   */
  500.                  while (pevent->OSEventGrp != 0) {         /* Yes, ready ALL tasks waiting on queue    */
  501.                      (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
  502.                      nbr_tasks++;
  503.                  }
  504.                  break;
  505.                
  506.             case OS_PEND_OPT_NONE:
  507.             default:                                       /* No,  ready HPT       waiting on queue    */
  508.                  (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
  509.                  nbr_tasks++;
  510.                  break;
  511.         }
  512.         OS_EXIT_CRITICAL();
  513.         OS_Sched();                                        /* Find HPT ready to run                    */
  514.         *perr = OS_ERR_PEND_ABORT;
  515.         return (nbr_tasks);
  516.     }
  517.     OS_EXIT_CRITICAL();
  518.     *perr = OS_ERR_NONE;
  519.     return (0);                                            /* No tasks waiting on queue                */
  520. }
  521. #endif
  522. /*$PAGE*/
  523. /*
  524. *********************************************************************************************************
  525. *                                        POST MESSAGE TO A QUEUE
  526. *
  527. * Description: This function sends a message to a queue
  528. *
  529. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  530. *
  531. *              pmsg          is a pointer to the message to send.
  532. *
  533. * Returns    : OS_ERR_NONE           The call was successful and the message was sent
  534. *              OS_ERR_Q_FULL         If the queue cannot accept any more messages because it is full.
  535. *              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
  536. *              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
  537. *
  538. * Note(s)    : As of V2.60, this function allows you to send NULL pointer messages.
  539. *********************************************************************************************************
  540. */
  541. #if OS_Q_POST_EN > 0
  542. INT8U  OSQPost (OS_EVENT  *pevent, 
  543.                 void      *pmsg)
  544. {
  545.     OS_Q      *pq;
  546. #if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
  547.     OS_CPU_SR  cpu_sr = 0;
  548. #endif
  549. #if OS_ARG_CHK_EN > 0
  550.     if (pevent == (OS_EVENT *)0) {                     /* Validate 'pevent'                            */
  551.         return (OS_ERR_PEVENT_NULL);
  552.     }
  553. #endif
  554.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {      /* Validate event block type                    */
  555.         return (OS_ERR_EVENT_TYPE);
  556.     }
  557.     OS_ENTER_CRITICAL();
  558.     if (pevent->OSEventGrp != 0) {                     /* See if any task pending on queue             */
  559.                                                        /* Ready highest priority task waiting on event */
  560.         (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  561.         OS_EXIT_CRITICAL();
  562.         OS_Sched();                                    /* Find highest priority task ready to run      */
  563.         return (OS_ERR_NONE);
  564.     }
  565.     pq = (OS_Q *)pevent->OSEventPtr;                   /* Point to queue control block                 */
  566.     if (pq->OSQEntries >= pq->OSQSize) {               /* Make sure queue is not full                  */
  567.         OS_EXIT_CRITICAL();
  568.         return (OS_ERR_Q_FULL);
  569.     }
  570.     *pq->OSQIn++ = pmsg;                               /* Insert message into queue                    */
  571.     pq->OSQEntries++;                                  /* Update the nbr of entries in the queue       */
  572.     if (pq->OSQIn == pq->OSQEnd) {                     /* Wrap IN ptr if we are at end of queue        */
  573.         pq->OSQIn = pq->OSQStart;
  574.     }
  575.     OS_EXIT_CRITICAL();
  576.     return (OS_ERR_NONE);
  577. }
  578. #endif
  579. /*$PAGE*/
  580. /*
  581. *********************************************************************************************************
  582. *                                   POST MESSAGE TO THE FRONT OF A QUEUE
  583. *
  584. * Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
  585. *              the front instead of the end of the queue.  Using OSQPostFront() allows you to send
  586. *              'priority' messages.
  587. *
  588. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  589. *
  590. *              pmsg          is a pointer to the message to send.
  591. *
  592. * Returns    : OS_ERR_NONE           The call was successful and the message was sent
  593. *              OS_ERR_Q_FULL         If the queue cannot accept any more messages because it is full.
  594. *              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
  595. *              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
  596. *
  597. * Note(s)    : As of V2.60, this function allows you to send NULL pointer messages.
  598. *********************************************************************************************************
  599. */
  600. #if OS_Q_POST_FRONT_EN > 0
  601. INT8U  OSQPostFront (OS_EVENT  *pevent, 
  602.                      void      *pmsg)
  603. {
  604.     OS_Q      *pq;
  605. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  606.     OS_CPU_SR  cpu_sr = 0;
  607. #endif
  608. #if OS_ARG_CHK_EN > 0
  609.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  610.         return (OS_ERR_PEVENT_NULL);
  611.     }
  612. #endif
  613.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  614.         return (OS_ERR_EVENT_TYPE);
  615.     }
  616.     OS_ENTER_CRITICAL();
  617.     if (pevent->OSEventGrp != 0) {                    /* See if any task pending on queue              */
  618.                                                       /* Ready highest priority task waiting on event  */
  619.         (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  620.         OS_EXIT_CRITICAL();
  621.         OS_Sched();                                   /* Find highest priority task ready to run       */
  622.         return (OS_ERR_NONE);
  623.     }
  624.     pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
  625.     if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
  626.         OS_EXIT_CRITICAL();
  627.         return (OS_ERR_Q_FULL);
  628.     }
  629.     if (pq->OSQOut == pq->OSQStart) {                 /* Wrap OUT ptr if we are at the 1st queue entry */
  630.         pq->OSQOut = pq->OSQEnd;
  631.     }
  632.     pq->OSQOut--;
  633.     *pq->OSQOut = pmsg;                               /* Insert message into queue                     */
  634.     pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
  635.     OS_EXIT_CRITICAL();
  636.     return (OS_ERR_NONE);
  637. }
  638. #endif
  639. /*$PAGE*/
  640. /*
  641. *********************************************************************************************************
  642. *                                        POST MESSAGE TO A QUEUE
  643. *
  644. * Description: This function sends a message to a queue.  This call has been added to reduce code size
  645. *              since it can replace both OSQPost() and OSQPostFront().  Also, this function adds the
  646. *              capability to broadcast a message to ALL tasks waiting on the message queue.
  647. *
  648. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  649. *
  650. *              pmsg          is a pointer to the message to send.
  651. *
  652. *              opt           determines the type of POST performed:
  653. *                            OS_POST_OPT_NONE         POST to a single waiting task
  654. *                                                     (Identical to OSQPost())
  655. *                            OS_POST_OPT_BROADCAST    POST to ALL tasks that are waiting on the queue
  656. *                            OS_POST_OPT_FRONT        POST as LIFO (Simulates OSQPostFront())
  657. *                            OS_POST_OPT_NO_SCHED     Indicates that the scheduler will NOT be invoked
  658. *
  659. * Returns    : OS_ERR_NONE           The call was successful and the message was sent
  660. *              OS_ERR_Q_FULL         If the queue cannot accept any more messages because it is full.
  661. *              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
  662. *              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
  663. *
  664. * Warning    : Interrupts can be disabled for a long time if you do a 'broadcast'.  In fact, the
  665. *              interrupt disable time is proportional to the number of tasks waiting on the queue.
  666. *********************************************************************************************************
  667. */
  668. #if OS_Q_POST_OPT_EN > 0
  669. INT8U  OSQPostOpt (OS_EVENT  *pevent, 
  670.                    void      *pmsg, 
  671.                    INT8U      opt)
  672. {
  673.     OS_Q      *pq;
  674. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  675.     OS_CPU_SR  cpu_sr = 0;
  676. #endif
  677. #if OS_ARG_CHK_EN > 0
  678.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  679.         return (OS_ERR_PEVENT_NULL);
  680.     }
  681. #endif
  682.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  683.         return (OS_ERR_EVENT_TYPE);
  684.     }
  685.     OS_ENTER_CRITICAL();
  686.     if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
  687.         if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* Do we need to post msg to ALL waiting tasks ? */
  688.             while (pevent->OSEventGrp != 0) {         /* Yes, Post to ALL tasks waiting on queue       */
  689.                 (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  690.             }
  691.         } else {                                      /* No,  Post to HPT waiting on queue             */
  692.             (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  693.         }
  694.         OS_EXIT_CRITICAL();
  695.         if ((opt & OS_POST_OPT_NO_SCHED) == 0) {   /* See if scheduler needs to be invoked          */
  696.             OS_Sched();                               /* Find highest priority task ready to run       */
  697.         }
  698.         return (OS_ERR_NONE);
  699.     }
  700.     pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
  701.     if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
  702.         OS_EXIT_CRITICAL();
  703.         return (OS_ERR_Q_FULL);
  704.     }
  705.     if ((opt & OS_POST_OPT_FRONT) != 0x00) {          /* Do we post to the FRONT of the queue?         */
  706.         if (pq->OSQOut == pq->OSQStart) {             /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
  707.             pq->OSQOut = pq->OSQEnd;                  /*      ... are at the 1st queue entry           */
  708.         }
  709.         pq->OSQOut--;
  710.         *pq->OSQOut = pmsg;                           /*      Insert message into queue                */
  711.     } else {                                          /* No,  Post as FIFO                             */
  712.         *pq->OSQIn++ = pmsg;                          /*      Insert message into queue                */
  713.         if (pq->OSQIn == pq->OSQEnd) {                /*      Wrap IN ptr if we are at end of queue    */
  714.             pq->OSQIn = pq->OSQStart;
  715.         }
  716.     }
  717.     pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
  718.     OS_EXIT_CRITICAL();
  719.     return (OS_ERR_NONE);
  720. }
  721. #endif
  722. /*$PAGE*/
  723. /*
  724. *********************************************************************************************************
  725. *                                        QUERY A MESSAGE QUEUE
  726. *
  727. * Description: This function obtains information about a message queue.
  728. *
  729. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  730. *
  731. *              p_q_data      is a pointer to a structure that will contain information about the message
  732. *                            queue.
  733. *
  734. * Returns    : OS_ERR_NONE         The call was successful and the message was sent
  735. *              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non queue.
  736. *              OS_ERR_PEVENT_NULL  If 'pevent'   is a NULL pointer
  737. *              OS_ERR_PDATA_NULL   If 'p_q_data' is a NULL pointer
  738. *********************************************************************************************************
  739. */
  740. #if OS_Q_QUERY_EN > 0
  741. INT8U  OSQQuery (OS_EVENT  *pevent, 
  742.                  OS_Q_DATA *p_q_data)
  743. {
  744.     OS_Q      *pq;
  745.     INT8U      i;
  746. #if OS_LOWEST_PRIO <= 63
  747.     INT8U     *psrc;
  748.     INT8U     *pdest;
  749. #else
  750.     INT16U    *psrc;
  751.     INT16U    *pdest;
  752. #endif
  753. #if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
  754.     OS_CPU_SR  cpu_sr = 0;
  755. #endif
  756. #if OS_ARG_CHK_EN > 0
  757.     if (pevent == (OS_EVENT *)0) {                     /* Validate 'pevent'                            */
  758.         return (OS_ERR_PEVENT_NULL);
  759.     }
  760.     if (p_q_data == (OS_Q_DATA *)0) {                  /* Validate 'p_q_data'                          */
  761.         return (OS_ERR_PDATA_NULL);
  762.     }
  763. #endif
  764.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {      /* Validate event block type                    */
  765.         return (OS_ERR_EVENT_TYPE);
  766.     }
  767.     OS_ENTER_CRITICAL();
  768.     p_q_data->OSEventGrp = pevent->OSEventGrp;         /* Copy message queue wait list                 */
  769.     psrc                 = &pevent->OSEventTbl[0];
  770.     pdest                = &p_q_data->OSEventTbl[0];
  771.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  772.         *pdest++ = *psrc++;
  773.     }
  774.     pq = (OS_Q *)pevent->OSEventPtr;
  775.     if (pq->OSQEntries > 0) {
  776.         p_q_data->OSMsg = *pq->OSQOut;                 /* Get next message to return if available      */
  777.     } else {
  778.         p_q_data->OSMsg = (void *)0;
  779.     }
  780.     p_q_data->OSNMsgs = pq->OSQEntries;
  781.     p_q_data->OSQSize = pq->OSQSize;
  782.     OS_EXIT_CRITICAL();
  783.     return (OS_ERR_NONE);
  784. }
  785. #endif                                                 /* OS_Q_QUERY_EN                                */
  786. /*$PAGE*/
  787. /*
  788. *********************************************************************************************************
  789. *                                      QUEUE MODULE INITIALIZATION
  790. *
  791. * Description : This function is called by uC/OS-II to initialize the message queue module.  Your
  792. *               application MUST NOT call this function.
  793. *
  794. * Arguments   :  none
  795. *
  796. * Returns     : none
  797. *
  798. * Note(s)    : This function is INTERNAL to uC/OS-II and your application should not call it.
  799. *********************************************************************************************************
  800. */
  801. void  OS_QInit (void)
  802. {
  803. #if OS_MAX_QS == 1
  804.     OSQFreeList         = &OSQTbl[0];                /* Only ONE queue!                                */
  805.     OSQFreeList->OSQPtr = (OS_Q *)0;
  806. #endif
  807. #if OS_MAX_QS >= 2
  808.     INT16U  i;
  809.     OS_Q   *pq1;
  810.     OS_Q   *pq2;
  811.     OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl));  /* Clear the queue table                          */
  812.     pq1 = &OSQTbl[0];
  813.     pq2 = &OSQTbl[1];
  814.     for (i = 0; i < (OS_MAX_QS - 1); i++) {          /* Init. list of free QUEUE control blocks        */
  815.         pq1->OSQPtr = pq2;
  816.         pq1++;
  817.         pq2++;
  818.     }
  819.     pq1->OSQPtr = (OS_Q *)0;
  820.     OSQFreeList = &OSQTbl[0];
  821. #endif
  822. }
  823. #endif                                               /* OS_Q_EN                                        */