OS_Q.C
上传用户:ssllxx2007
上传日期:2022-06-12
资源大小:784k
文件大小:34k
源码类别:

uCOS

开发平台:

C/C++

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