os_q.c
上传用户:dongxin
上传日期:2022-06-22
资源大小:370k
文件大小:41k
源码类别:

uCOS

开发平台:

Others

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