OS_Q.C
上传用户:zfj3589
上传日期:2022-07-13
资源大小:635k
文件大小:34k
源码类别:

微处理器开发

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                        MESSAGE QUEUE MANAGEMENT
  6. *
  7. *                          (c) Copyright 1992-2001, Jean J. Labrosse, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File : OS_Q.C
  11. * By   : Jean J. Labrosse
  12. *********************************************************************************************************
  13. */
  14. #ifndef  OS_MASTER_FILE
  15. #include "includes.h"
  16. #endif
  17. #if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
  18. /*
  19. *********************************************************************************************************
  20. *                                      ACCEPT MESSAGE FROM QUEUE
  21. *
  22. * Description: This function checks the queue to see if a message is available.  Unlike OSQPend(),
  23. *              OSQAccept() does not suspend the calling task if a message is not available.
  24. *
  25. * Arguments  : pevent        is a pointer to the event control block
  26. *
  27. * Returns    : != (void *)0  is the message in the queue if one is available.  The message is removed
  28. *                            from the so the next time OSQAccept() is called, the queue will contain
  29. *                            one less entry.
  30. *              == (void *)0  if the queue is empty or,
  31. *                            if 'pevent' is a NULL pointer or,
  32. *                            if you passed an invalid event type
  33. *********************************************************************************************************
  34. */
  35. #if OS_Q_ACCEPT_EN > 0
  36. void  *OSQAccept (OS_EVENT *pevent)
  37. {
  38. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  39.     OS_CPU_SR  cpu_sr;
  40. #endif    
  41.     void      *msg;
  42.     OS_Q      *pq;
  43. #if OS_ARG_CHK_EN > 0
  44.     if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
  45.         return ((void *)0);
  46.     }
  47.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
  48.         return ((void *)0);
  49.     }
  50. #endif
  51.     OS_ENTER_CRITICAL();
  52.     pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
  53.     if (pq->OSQEntries != 0) {                   /* See if any messages in the queue                   */
  54.         msg = *pq->OSQOut++;                     /* Yes, extract oldest message from the queue         */
  55.         pq->OSQEntries--;                        /* Update the number of entries in the queue          */
  56.         if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
  57.             pq->OSQOut = pq->OSQStart;
  58.         }
  59.     } else {
  60.         msg = (void *)0;                         /* Queue is empty                                     */
  61.     }
  62.     OS_EXIT_CRITICAL();
  63.     return (msg);                                /* Return message received (or NULL)                  */
  64. }
  65. #endif
  66. /*$PAGE*/
  67. /*
  68. *********************************************************************************************************
  69. *                                        CREATE A MESSAGE QUEUE
  70. *
  71. * Description: This function creates a message queue if free event control blocks are available.
  72. *
  73. * Arguments  : start         is a pointer to the base address of the message queue storage area.  The
  74. *                            storage area MUST be declared as an array of pointers to 'void' as follows
  75. *
  76. *                            void *MessageStorage[size]
  77. *
  78. *              size          is the number of elements in the storage area
  79. *
  80. * Returns    : != (OS_EVENT *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  81. *                                created queue
  82. *              == (OS_EVENT *)0  if no event control blocks were available or an error was detected
  83. *********************************************************************************************************
  84. */
  85. OS_EVENT  *OSQCreate (void **start, INT16U size)
  86. {
  87. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  88.     OS_CPU_SR  cpu_sr;
  89. #endif    
  90.     OS_EVENT  *pevent;
  91.     OS_Q      *pq;
  92.     if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
  93.         return ((OS_EVENT *)0);                  /* ... can't CREATE from an ISR                       */
  94.     }
  95.     OS_ENTER_CRITICAL();
  96.     pevent = OSEventFreeList;                    /* Get next free event control block                  */
  97.     if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
  98.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  99.     }
  100.     OS_EXIT_CRITICAL();
  101.     if (pevent != (OS_EVENT *)0) {               /* See if we have an event control block              */
  102.         OS_ENTER_CRITICAL();                     /* Get a free queue control block                     */
  103.         pq = OSQFreeList;
  104.         if (OSQFreeList != (OS_Q *)0) {
  105.             OSQFreeList = OSQFreeList->OSQPtr;
  106.         }
  107.         OS_EXIT_CRITICAL();
  108.         if (pq != (OS_Q *)0) {                   /* See if we were able to get a queue control block   */
  109.             pq->OSQStart        = start;         /* Yes, initialize the queue                          */
  110.             pq->OSQEnd          = &start[size];
  111.             pq->OSQIn           = start;
  112.             pq->OSQOut          = start;
  113.             pq->OSQSize         = size;
  114.             pq->OSQEntries      = 0;
  115.             pevent->OSEventType = OS_EVENT_TYPE_Q;
  116.             pevent->OSEventPtr  = pq;
  117.             OS_EventWaitListInit(pevent);
  118.         } else {                                 /* No,  since we couldn't get a queue control block   */
  119.             OS_ENTER_CRITICAL();                 /* Return event control block on error                */
  120.             pevent->OSEventPtr = (void *)OSEventFreeList;
  121.             OSEventFreeList    = pevent;
  122.             OS_EXIT_CRITICAL();
  123.             pevent = (OS_EVENT *)0;
  124.         }
  125.     }
  126.     return (pevent);
  127. }
  128. /*$PAGE*/
  129. /*
  130. *********************************************************************************************************
  131. *                                        DELETE A MESSAGE QUEUE
  132. *
  133. * Description: This function deletes a message queue and readies all tasks pending on the queue.
  134. *
  135. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  136. *                            queue.
  137. *
  138. *              opt           determines delete options as follows:
  139. *                            opt == OS_DEL_NO_PEND   Delete the queue ONLY if no task pending
  140. *                            opt == OS_DEL_ALWAYS    Deletes the queue even if tasks are waiting.
  141. *                                                    In this case, all the tasks pending will be readied.
  142. *
  143. *              err           is a pointer to an error code that can contain one of the following values:
  144. *                            OS_NO_ERR               The call was successful and the queue was deleted
  145. *                            OS_ERR_DEL_ISR          If you tried to delete the queue from an ISR
  146. *                            OS_ERR_INVALID_OPT      An invalid option was specified
  147. *                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the queue
  148. *                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a queue
  149. *                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
  150. *
  151. * Returns    : pevent        upon error
  152. *              (OS_EVENT *)0 if the queue was successfully deleted.
  153. *
  154. * Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
  155. *                 the queue MUST check the return code of OSQPend().
  156. *              2) OSQAccept() callers will not know that the intended queue has been deleted unless
  157. *                 they check 'pevent' to see that it's a NULL pointer.
  158. *              3) This call can potentially disable interrupts for a long time.  The interrupt disable
  159. *                 time is directly proportional to the number of tasks waiting on the queue.
  160. *              4) Because ALL tasks pending on the queue will be readied, you MUST be careful in
  161. *                 applications where the queue is used for mutual exclusion because the resource(s)
  162. *                 will no longer be guarded by the queue.
  163. *              5) If the storage for the message queue was allocated dynamically (i.e. using a malloc()
  164. *                 type call) then your application MUST release the memory storage by call the counterpart
  165. *                 call of the dynamic allocation scheme used.  If the queue storage was created statically
  166. *                 then, the storage can be reused.
  167. *********************************************************************************************************
  168. */
  169. #if OS_Q_DEL_EN > 0
  170. OS_EVENT  *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  171. {
  172. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  173.     OS_CPU_SR  cpu_sr;
  174. #endif    
  175.     BOOLEAN    tasks_waiting;
  176.     OS_Q      *pq;
  177.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  178.         *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
  179.         return ((OS_EVENT *)0);
  180.     }
  181. #if OS_ARG_CHK_EN > 0
  182.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  183.         *err = OS_ERR_PEVENT_NULL;
  184.         return (pevent);
  185.     }
  186.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
  187.         *err = OS_ERR_EVENT_TYPE;
  188.         return (pevent);
  189.     }
  190. #endif
  191.     OS_ENTER_CRITICAL();
  192.     if (pevent->OSEventGrp != 0x00) {                      /* See if any tasks waiting on queue        */
  193.         tasks_waiting = TRUE;                              /* Yes                                      */
  194.     } else {
  195.         tasks_waiting = FALSE;                             /* No                                       */
  196.     }
  197.     switch (opt) {
  198.         case OS_DEL_NO_PEND:                               /* Delete queue only if no task waiting     */
  199.              if (tasks_waiting == FALSE) {
  200.                  pq                  = pevent->OSEventPtr; /* Return OS_Q to free list                 */ 
  201.                  pq->OSQPtr          = OSQFreeList;
  202.                  OSQFreeList         = pq;
  203.                  pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  204.                  pevent->OSEventPtr  = OSEventFreeList;    /* Return Event Control Block to free list  */
  205.                  OSEventFreeList     = pevent;             /* Get next free event control block        */
  206.                  OS_EXIT_CRITICAL();
  207.                  *err = OS_NO_ERR;
  208.                  return ((OS_EVENT *)0);                   /* Queue has been deleted                   */
  209.              } else {
  210.                  OS_EXIT_CRITICAL();
  211.                  *err = OS_ERR_TASK_WAITING;
  212.                  return (pevent);
  213.              }
  214.         case OS_DEL_ALWAYS:                                /* Always delete the queue                  */
  215.              while (pevent->OSEventGrp != 0x00) {          /* Ready ALL tasks waiting for queue        */
  216.                  OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q);
  217.              }
  218.              pq                  = pevent->OSEventPtr;     /* Return OS_Q to free list                 */ 
  219.              pq->OSQPtr          = OSQFreeList;
  220.              OSQFreeList         = pq;
  221.              pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  222.              pevent->OSEventPtr  = OSEventFreeList;        /* Return Event Control Block to free list  */
  223.              OSEventFreeList     = pevent;                 /* Get next free event control block        */
  224.              OS_EXIT_CRITICAL();
  225.              if (tasks_waiting == TRUE) {                  /* Reschedule only if task(s) were waiting  */
  226.                  OS_Sched();                               /* Find highest priority task ready to run  */
  227.              }
  228.              *err = OS_NO_ERR;
  229.              return ((OS_EVENT *)0);                       /* Queue has been deleted                   */
  230.         default:
  231.              OS_EXIT_CRITICAL();
  232.              *err = OS_ERR_INVALID_OPT;
  233.              return (pevent);
  234.     }
  235. }
  236. #endif
  237. /*$PAGE*/
  238. /*
  239. *********************************************************************************************************
  240. *                                           FLUSH QUEUE
  241. *
  242. * Description : This function is used to flush the contents of the message queue.
  243. *
  244. * Arguments   : none
  245. *
  246. * Returns     : OS_NO_ERR           upon success
  247. *               OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a queue
  248. *               OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  249. *********************************************************************************************************
  250. */
  251. #if OS_Q_FLUSH_EN > 0
  252. INT8U  OSQFlush (OS_EVENT *pevent)
  253. {
  254. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  255.     OS_CPU_SR  cpu_sr;
  256. #endif    
  257.     OS_Q      *pq;
  258. #if OS_ARG_CHK_EN > 0
  259.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  260.         return (OS_ERR_PEVENT_NULL);
  261.     }
  262.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  263.         return (OS_ERR_EVENT_TYPE);
  264.     }
  265. #endif
  266.     OS_ENTER_CRITICAL();
  267.     pq             = (OS_Q *)pevent->OSEventPtr;      /* Point to queue storage structure              */
  268.     pq->OSQIn      = pq->OSQStart;
  269.     pq->OSQOut     = pq->OSQStart;
  270.     pq->OSQEntries = 0;
  271.     OS_EXIT_CRITICAL();
  272.     return (OS_NO_ERR);
  273. }
  274. #endif
  275. /*$PAGE*/
  276. /*
  277. *********************************************************************************************************
  278. *                                     PEND ON A QUEUE FOR A MESSAGE
  279. *
  280. * Description: This function waits for a message to be sent to a queue
  281. *
  282. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  283. *
  284. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  285. *                            wait for a message to arrive at the queue up to the amount of time
  286. *                            specified by this argument.  If you specify 0, however, your task will wait
  287. *                            forever at the specified queue or, until a message arrives.
  288. *
  289. *              err           is a pointer to where an error message will be deposited.  Possible error
  290. *                            messages are:
  291. *
  292. *                            OS_NO_ERR           The call was successful and your task received a
  293. *                                                message.
  294. *                            OS_TIMEOUT          A message was not received within the specified timeout
  295. *                            OS_ERR_EVENT_TYPE   You didn't pass a pointer to a queue
  296. *                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  297. *                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
  298. *                                                would lead to a suspension.
  299. *
  300. * Returns    : != (void *)0  is a pointer to the message received
  301. *              == (void *)0  if no message was received or,
  302. *                            if 'pevent' is a NULL pointer or,
  303. *                            if you didn't pass a pointer to a queue.
  304. *********************************************************************************************************
  305. */
  306. void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  307. {
  308. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  309.     OS_CPU_SR  cpu_sr;
  310. #endif    
  311.     void      *msg;
  312.     OS_Q      *pq;
  313.     if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
  314.         *err = OS_ERR_PEND_ISR;                  /* ... can't PEND from an ISR                         */
  315.         return ((void *)0);
  316.     }
  317. #if OS_ARG_CHK_EN > 0
  318.     if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
  319.         *err = OS_ERR_PEVENT_NULL;
  320.         return ((void *)0);
  321.     }
  322.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
  323.         *err = OS_ERR_EVENT_TYPE;
  324.         return ((void *)0);
  325.     }
  326. #endif
  327.     OS_ENTER_CRITICAL();
  328.     pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
  329.     if (pq->OSQEntries != 0) {                   /* See if any messages in the queue                   */
  330.         msg = *pq->OSQOut++;                     /* Yes, extract oldest message from the queue         */
  331.         pq->OSQEntries--;                        /* Update the number of entries in the queue          */
  332.         if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
  333.             pq->OSQOut = pq->OSQStart;
  334.         }
  335.         OS_EXIT_CRITICAL();
  336.         *err = OS_NO_ERR;
  337.         return (msg);                            /* Return message received                            */
  338.     }
  339.     OSTCBCur->OSTCBStat |= OS_STAT_Q;            /* Task will have to pend for a message to be posted  */
  340.     OSTCBCur->OSTCBDly   = timeout;              /* Load timeout into TCB                              */
  341.     OS_EventTaskWait(pevent);                    /* Suspend task until event or timeout occurs         */
  342.     OS_EXIT_CRITICAL();
  343.     OS_Sched();                                  /* Find next highest priority task ready to run       */
  344.     OS_ENTER_CRITICAL();
  345.     msg = OSTCBCur->OSTCBMsg;
  346.     if (msg != (void *)0) {                      /* Did we get a message?                              */
  347.         OSTCBCur->OSTCBMsg      = (void *)0;     /* Extract message from TCB (Put there by QPost)      */
  348.         OSTCBCur->OSTCBStat     = OS_STAT_RDY;
  349.         OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event                        */
  350.         OS_EXIT_CRITICAL();
  351.         *err                    = OS_NO_ERR;
  352.         return (msg);                            /* Return message received                            */
  353.     }
  354.     OS_EventTO(pevent);                          /* Timed out                                          */
  355.     OS_EXIT_CRITICAL();
  356.     *err = OS_TIMEOUT;                           /* Indicate a timeout occured                         */
  357.     return ((void *)0);                          /* No message received                                */
  358. }
  359. /*$PAGE*/
  360. /*
  361. *********************************************************************************************************
  362. *                                        POST MESSAGE TO A QUEUE
  363. *
  364. * Description: This function sends a message to a queue
  365. *
  366. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  367. *
  368. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
  369. *
  370. * Returns    : OS_NO_ERR             The call was successful and the message was sent
  371. *              OS_Q_FULL             If the queue cannot accept any more messages because it is full.
  372. *              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
  373. *              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
  374. *              OS_ERR_POST_NULL_PTR  If you are attempting to post a NULL pointer
  375. *********************************************************************************************************
  376. */
  377. #if OS_Q_POST_EN > 0
  378. INT8U  OSQPost (OS_EVENT *pevent, void *msg)
  379. {
  380. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  381.     OS_CPU_SR  cpu_sr;
  382. #endif    
  383.     OS_Q      *pq;
  384. #if OS_ARG_CHK_EN > 0
  385.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  386.         return (OS_ERR_PEVENT_NULL);
  387.     }
  388.     if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
  389.         return (OS_ERR_POST_NULL_PTR);
  390.     }
  391.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  392.         return (OS_ERR_EVENT_TYPE);
  393.     }
  394. #endif
  395.     OS_ENTER_CRITICAL();
  396.     if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
  397.         OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* Ready highest priority task waiting on event  */
  398.         OS_EXIT_CRITICAL();
  399.         OS_Sched();                                   /* Find highest priority task ready to run       */
  400.         return (OS_NO_ERR);
  401.     }
  402.     pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
  403.     if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
  404.         OS_EXIT_CRITICAL();
  405.         return (OS_Q_FULL);
  406.     }
  407.     *pq->OSQIn++ = msg;                               /* Insert message into queue                     */
  408.     pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
  409.     if (pq->OSQIn == pq->OSQEnd) {                    /* Wrap IN ptr if we are at end of queue         */
  410.         pq->OSQIn = pq->OSQStart;
  411.     }
  412.     OS_EXIT_CRITICAL();
  413.     return (OS_NO_ERR);
  414. }
  415. #endif
  416. /*$PAGE*/
  417. /*
  418. *********************************************************************************************************
  419. *                                   POST MESSAGE TO THE FRONT OF A QUEUE
  420. *
  421. * Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
  422. *              the front instead of the end of the queue.  Using OSQPostFront() allows you to send
  423. *              'priority' messages.
  424. *
  425. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  426. *
  427. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
  428. *
  429. * Returns    : OS_NO_ERR             The call was successful and the message was sent
  430. *              OS_Q_FULL             If the queue cannot accept any more messages because it is full.
  431. *              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
  432. *              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
  433. *              OS_ERR_POST_NULL_PTR  If you are attempting to post to a non queue.
  434. *********************************************************************************************************
  435. */
  436. #if OS_Q_POST_FRONT_EN > 0
  437. INT8U  OSQPostFront (OS_EVENT *pevent, void *msg)
  438. {
  439. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  440.     OS_CPU_SR  cpu_sr;
  441. #endif    
  442.     OS_Q      *pq;
  443. #if OS_ARG_CHK_EN > 0
  444.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  445.         return (OS_ERR_PEVENT_NULL);
  446.     }
  447.     if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
  448.         return (OS_ERR_POST_NULL_PTR);
  449.     }
  450.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  451.         return (OS_ERR_EVENT_TYPE);
  452.     }
  453. #endif
  454.     OS_ENTER_CRITICAL();
  455.     if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
  456.         OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* Ready highest priority task waiting on event  */
  457.         OS_EXIT_CRITICAL();
  458.         OS_Sched();                                   /* Find highest priority task ready to run       */
  459.         return (OS_NO_ERR);
  460.     }
  461.     pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
  462.     if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
  463.         OS_EXIT_CRITICAL();
  464.         return (OS_Q_FULL);
  465.     }
  466.     if (pq->OSQOut == pq->OSQStart) {                 /* Wrap OUT ptr if we are at the 1st queue entry */
  467.         pq->OSQOut = pq->OSQEnd;
  468.     }
  469.     pq->OSQOut--;
  470.     *pq->OSQOut = msg;                                /* Insert message into queue                     */
  471.     pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
  472.     OS_EXIT_CRITICAL();
  473.     return (OS_NO_ERR);
  474. }
  475. #endif
  476. /*$PAGE*/
  477. /*
  478. *********************************************************************************************************
  479. *                                        POST MESSAGE TO A QUEUE
  480. *
  481. * Description: This function sends a message to a queue.  This call has been added to reduce code size
  482. *              since it can replace both OSQPost() and OSQPostFront().  Also, this function adds the 
  483. *              capability to broadcast a message to ALL tasks waiting on the message queue.
  484. *
  485. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  486. *
  487. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
  488. *
  489. *              opt           determines the type of POST performed:
  490. *                            OS_POST_OPT_NONE         POST to a single waiting task 
  491. *                                                     (Identical to OSQPost())
  492. *                            OS_POST_OPT_BROADCAST    POST to ALL tasks that are waiting on the queue
  493. *                            OS_POST_OPT_FRONT        POST as LIFO (Simulates OSQPostFront())
  494. *
  495. *                            Below is a list of ALL the possible combination of these flags:
  496. *
  497. *                                 1) OS_POST_OPT_NONE
  498. *                                    identical to OSQPost()
  499. *
  500. *                                 2) OS_POST_OPT_FRONT  
  501. *                                    identical to OSQPostFront()
  502. *
  503. *                                 3) OS_POST_OPT_BROADCAST
  504. *                                    identical to OSQPost() but will broadcast 'msg' to ALL waiting tasks
  505. *
  506. *                                 4) OS_POST_OPT_FRONT + OS_POST_OPT_BROADCAST  is identical to
  507. *                                    OSQPostFront() except that will broadcast 'msg' to ALL waiting tasks
  508. *
  509. * Returns    : OS_NO_ERR             The call was successful and the message was sent
  510. *              OS_Q_FULL             If the queue cannot accept any more messages because it is full.
  511. *              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
  512. *              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
  513. *              OS_ERR_POST_NULL_PTR  If you are attempting to post a NULL pointer
  514. *
  515. * Warning    : Interrupts can be disabled for a long time if you do a 'broadcast'.  In fact, the 
  516. *              interrupt disable time is proportional to the number of tasks waiting on the queue.
  517. *********************************************************************************************************
  518. */
  519. #if OS_Q_POST_OPT_EN > 0
  520. INT8U  OSQPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
  521. {
  522. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  523.     OS_CPU_SR  cpu_sr;
  524. #endif    
  525.     OS_Q      *pq;
  526. #if OS_ARG_CHK_EN > 0
  527.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  528.         return (OS_ERR_PEVENT_NULL);
  529.     }
  530.     if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
  531.         return (OS_ERR_POST_NULL_PTR);
  532.     }
  533.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  534.         return (OS_ERR_EVENT_TYPE);
  535.     }
  536. #endif
  537.     OS_ENTER_CRITICAL();
  538.     if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
  539.         if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* Do we need to post msg to ALL waiting tasks ? */
  540.             while (pevent->OSEventGrp != 0x00) {      /* Yes, Post to ALL tasks waiting on queue       */           
  541.                 OS_EventTaskRdy(pevent, msg, OS_STAT_Q);    
  542.             }
  543.         } else {
  544.             OS_EventTaskRdy(pevent, msg, OS_STAT_Q);  /* No,  Post to HPT waiting on queue             */
  545.         }
  546.         OS_EXIT_CRITICAL();
  547.         OS_Sched();                                   /* Find highest priority task ready to run       */
  548.         return (OS_NO_ERR);
  549.     }
  550.     pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
  551.     if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
  552.         OS_EXIT_CRITICAL();
  553.         return (OS_Q_FULL);
  554.     }
  555.     if ((opt & OS_POST_OPT_FRONT) != 0x00) {          /* Do we post to the FRONT of the queue?         */
  556.         if (pq->OSQOut == pq->OSQStart) {             /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
  557.             pq->OSQOut = pq->OSQEnd;                  /*      ... are at the 1st queue entry           */
  558.         }
  559.         pq->OSQOut--;
  560.         *pq->OSQOut = msg;                            /*      Insert message into queue                */
  561.     } else {                                          /* No,  Post as FIFO                             */
  562.         *pq->OSQIn++ = msg;                           /*      Insert message into queue                */
  563.         if (pq->OSQIn == pq->OSQEnd) {                /*      Wrap IN ptr if we are at end of queue    */
  564.             pq->OSQIn = pq->OSQStart;
  565.         }
  566.     }
  567.     pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
  568.     OS_EXIT_CRITICAL();
  569.     return (OS_NO_ERR);
  570. }
  571. #endif
  572. /*$PAGE*/
  573. /*
  574. *********************************************************************************************************
  575. *                                        QUERY A MESSAGE QUEUE
  576. *
  577. * Description: This function obtains information about a message queue.
  578. *
  579. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  580. *
  581. *              pdata         is a pointer to a structure that will contain information about the message
  582. *                            queue.
  583. *
  584. * Returns    : OS_NO_ERR           The call was successful and the message was sent
  585. *              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non queue.
  586. *              OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  587. *********************************************************************************************************
  588. */
  589. #if OS_Q_QUERY_EN > 0
  590. INT8U  OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata)
  591. {
  592. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  593.     OS_CPU_SR  cpu_sr;
  594. #endif    
  595.     OS_Q      *pq;
  596.     INT8U     *psrc;
  597.     INT8U     *pdest;
  598. #if OS_ARG_CHK_EN > 0
  599.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  600.         return (OS_ERR_PEVENT_NULL);
  601.     }
  602.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
  603.         return (OS_ERR_EVENT_TYPE);
  604.     }
  605. #endif
  606.     OS_ENTER_CRITICAL();
  607.     pdata->OSEventGrp = pevent->OSEventGrp;                /* Copy message queue wait list           */
  608.     psrc              = &pevent->OSEventTbl[0];
  609.     pdest             = &pdata->OSEventTbl[0];
  610. #if OS_EVENT_TBL_SIZE > 0
  611.     *pdest++          = *psrc++;
  612. #endif
  613. #if OS_EVENT_TBL_SIZE > 1
  614.     *pdest++          = *psrc++;
  615. #endif
  616. #if OS_EVENT_TBL_SIZE > 2
  617.     *pdest++          = *psrc++;
  618. #endif
  619. #if OS_EVENT_TBL_SIZE > 3
  620.     *pdest++          = *psrc++;
  621. #endif
  622. #if OS_EVENT_TBL_SIZE > 4
  623.     *pdest++          = *psrc++;
  624. #endif
  625. #if OS_EVENT_TBL_SIZE > 5
  626.     *pdest++          = *psrc++;
  627. #endif
  628. #if OS_EVENT_TBL_SIZE > 6
  629.     *pdest++          = *psrc++;
  630. #endif
  631. #if OS_EVENT_TBL_SIZE > 7
  632.     *pdest            = *psrc;
  633. #endif
  634.     pq = (OS_Q *)pevent->OSEventPtr;
  635.     if (pq->OSQEntries > 0) {
  636.         pdata->OSMsg = pq->OSQOut;                         /* Get next message to return if available  */
  637.     } else {
  638.         pdata->OSMsg = (void *)0;
  639.     }
  640.     pdata->OSNMsgs = pq->OSQEntries;
  641.     pdata->OSQSize = pq->OSQSize;
  642.     OS_EXIT_CRITICAL();
  643.     return (OS_NO_ERR);
  644. }
  645. #endif                                                     /* OS_Q_QUERY_EN                            */
  646. /*$PAGE*/
  647. /*
  648. *********************************************************************************************************
  649. *                                      QUEUE MODULE INITIALIZATION
  650. *
  651. * Description : This function is called by uC/OS-II to initialize the message queue module.  Your
  652. *               application MUST NOT call this function.
  653. *
  654. * Arguments   :  none
  655. *
  656. * Returns     : none
  657. *
  658. * Note(s)    : This function is INTERNAL to uC/OS-II and your application should not call it.
  659. *********************************************************************************************************
  660. */
  661. void  OS_QInit (void)
  662. {
  663. #if OS_MAX_QS == 1
  664.     OSQFreeList         = &OSQTbl[0];            /* Only ONE queue!                                    */
  665.     OSQFreeList->OSQPtr = (OS_Q *)0;
  666. #endif
  667. #if OS_MAX_QS >= 2
  668.     INT16U  i;
  669.     OS_Q   *pq1;
  670.     OS_Q   *pq2;
  671.     pq1 = &OSQTbl[0];
  672.     pq2 = &OSQTbl[1];
  673.     for (i = 0; i < (OS_MAX_QS - 1); i++) {      /* Init. list of free QUEUE control blocks            */
  674.         pq1->OSQPtr = pq2;
  675.         pq1++;
  676.         pq2++;
  677.     }
  678.     pq1->OSQPtr = (OS_Q *)0;
  679.     OSQFreeList = &OSQTbl[0];
  680. #endif
  681. }
  682. #endif                                                     /* OS_Q_EN                                  */