os_q.c
上传用户:zbk8730
上传日期:2017-08-10
资源大小:12168k
文件大小:36k
源码类别:

uCOS

开发平台:

C/C++

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