OS_Q.c
上传用户:jinguanrq
上传日期:2022-06-04
资源大小:724k
文件大小:20k
源码类别:

uCOS

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                        MESSAGE QUEUE MANAGEMENT
  6. *
  7. *                        (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
  8. *                                           All Rights Reserved
  9. *
  10. *                                                  V2.00
  11. *
  12. * File : OS_Q.C
  13. * By   : Jean J. Labrosse
  14. *********************************************************************************************************
  15. */
  16. #ifndef  OS_MASTER_FILE
  17. #include "includes.h"
  18. #endif
  19. #if OS_Q_EN && (OS_MAX_QS >= 2)
  20. /*
  21. *********************************************************************************************************
  22. *                                           LOCAL DATA TYPES  
  23. *********************************************************************************************************
  24. */
  25. typedef struct os_q {                  /* QUEUE CONTROL BLOCK                                          */
  26.     struct os_q   *OSQPtr;             /* Link to next queue control block in list of free blocks      */
  27.     void         **OSQStart;           /* Pointer to start of queue data                               */
  28.     void         **OSQEnd;             /* Pointer to end   of queue data                               */
  29.     void         **OSQIn;              /* Pointer to where next message will be inserted  in   the Q   */
  30.     void         **OSQOut;             /* Pointer to where next message will be extracted from the Q   */
  31.     INT16U         OSQSize;            /* Size of queue (maximum number of entries)                    */
  32.     INT16U         OSQEntries;         /* Current number of entries in the queue                       */
  33. } OS_Q;
  34. /*
  35. *********************************************************************************************************
  36. *                                         LOCAL GLOBAL VARIABLES
  37. *********************************************************************************************************
  38. */
  39. static  OS_Q        *OSQFreeList;              /* Pointer to list of free QUEUE control blocks         */
  40. static  OS_Q         OSQTbl[OS_MAX_QS];        /* Table of QUEUE control blocks                        */
  41. /*$PAGE*/
  42. /*
  43. *********************************************************************************************************
  44. *                                      ACCEPT MESSAGE FROM QUEUE
  45. *
  46. * Description: This function checks the queue to see if a message is available.  Unlike OSQPend(),
  47. *              OSQAccept() does not suspend the calling task if a message is not available.
  48. *
  49. * Arguments  : pevent        is a pointer to the event control block
  50. *
  51. * Returns    : != (void *)0  is the message in the queue if one is available.  The message is removed
  52. *                            from the so the next time OSQAccept() is called, the queue will contain
  53. *                            one less entry.
  54. *              == (void *)0  if the queue is empty
  55. *                            if you passed an invalid event type
  56. *********************************************************************************************************
  57. */
  58. void *OSQAccept (OS_EVENT *pevent)
  59. {
  60.     void  *msg;
  61.     OS_Q  *pq;
  62.     OS_ENTER_CRITICAL();
  63.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  64.         OS_EXIT_CRITICAL();
  65.         return ((void *)0);
  66.     }
  67.     pq = pevent->OSEventPtr;                     /* Point at queue control block                       */
  68.     if (pq->OSQEntries != 0) {                   /* See if any messages in the queue                   */
  69.         msg = *pq->OSQOut++;                     /* Yes, extract oldest message from the queue         */
  70.         pq->OSQEntries--;                        /* Update the number of entries in the queue          */
  71.         if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
  72.             pq->OSQOut = pq->OSQStart;
  73.         }
  74.     } else {
  75.         msg = (void *)0;                         /* Queue is empty                                     */
  76.     }
  77.     OS_EXIT_CRITICAL();
  78.     return (msg);                                /* Return message received (or NULL)                  */
  79. }
  80. /*$PAGE*/
  81. /*
  82. *********************************************************************************************************
  83. *                                        CREATE A MESSAGE QUEUE
  84. *
  85. * Description: This function creates a message queue if free event control blocks are available.
  86. *
  87. * Arguments  : start         is a pointer to the base address of the message queue storage area.  The
  88. *                            storage area MUST be declared as an array of pointers to 'void' as follows
  89. *
  90. *                            void *MessageStorage[size]
  91. *
  92. *              size          is the number of elements in the storage area
  93. *
  94. * Returns    : != (void *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  95. *                            created queue
  96. *              == (void *)0  if no event control blocks were available
  97. *********************************************************************************************************
  98. */
  99. OS_EVENT *OSQCreate (void **start, INT16U size)
  100. {
  101.     OS_EVENT *pevent;
  102.     OS_Q     *pq;
  103.     OS_ENTER_CRITICAL();
  104.     pevent = OSEventFreeList;                    /* Get next free event control block                  */
  105.     if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
  106.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  107.     }
  108.     OS_EXIT_CRITICAL();
  109.     if (pevent != (OS_EVENT *)0) {               /* See if we have an event control block              */
  110.         OS_ENTER_CRITICAL();                     /* Get a free queue control block                     */
  111.         pq = OSQFreeList;
  112.         if (OSQFreeList != (OS_Q *)0) {
  113.             OSQFreeList = OSQFreeList->OSQPtr;
  114.         }
  115.         OS_EXIT_CRITICAL();
  116.         if (pq != (OS_Q *)0) {                   /* See if we were able to get a queue control block   */
  117.             pq->OSQStart        = start;         /* Yes, initialize the queue                          */
  118.             pq->OSQEnd          = &start[size];
  119.             pq->OSQIn           = start;
  120.             pq->OSQOut          = start;
  121.             pq->OSQSize         = size;
  122.             pq->OSQEntries      = 0;
  123.             pevent->OSEventType = OS_EVENT_TYPE_Q;
  124.             pevent->OSEventPtr  = pq;
  125.             OSEventWaitListInit(pevent);
  126.         } else {                                 /* No,  since we couldn't get a queue control block   */
  127.             OS_ENTER_CRITICAL();                 /* Return event control block on error                */
  128.             pevent->OSEventPtr = (void *)OSEventFreeList;
  129.             OSEventFreeList    = pevent;
  130.             OS_EXIT_CRITICAL();
  131.             pevent = (OS_EVENT *)0;
  132.         }
  133.     }
  134.     return (pevent);
  135. }
  136. /*$PAGE*/
  137. /*
  138. *********************************************************************************************************
  139. *                                           FLUSH QUEUE
  140. *
  141. * Description : This function is used to flush the contents of the message queue.
  142. *
  143. * Arguments   : none
  144. *
  145. * Returns     : OS_NO_ERR          upon success
  146. *               OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a queue
  147. *********************************************************************************************************
  148. */
  149. INT8U OSQFlush (OS_EVENT *pevent)
  150. {
  151.     OS_Q  *pq;
  152.     
  153.     OS_ENTER_CRITICAL();
  154.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  155.         OS_EXIT_CRITICAL();
  156.         return (OS_ERR_EVENT_TYPE);
  157.     }
  158.     pq             = pevent->OSEventPtr;              /* Point to queue storage structure              */
  159.     pq->OSQIn      = pq->OSQStart;
  160.     pq->OSQOut     = pq->OSQStart;
  161.     pq->OSQEntries = 0;
  162.     OS_EXIT_CRITICAL();
  163.     return (OS_NO_ERR);
  164. }
  165. /*$PAGE*/
  166. /*
  167. *********************************************************************************************************
  168. *                                      QUEUE MODULE INITIALIZATION
  169. *
  170. * Description : This function is called by uC/OS-II to initialize the message queue module.  Your
  171. *               application MUST NOT call this function.
  172. *
  173. * Arguments   :  none
  174. *
  175. * Returns     : none
  176. *********************************************************************************************************
  177. */
  178. void OSQInit (void)
  179. {
  180.     INT16U i;
  181.     for (i = 0; i < (OS_MAX_QS - 1); i++) {      /* Init. list of free QUEUE control blocks            */
  182.         OSQTbl[i].OSQPtr = &OSQTbl[i+1];
  183.     }
  184.     OSQTbl[OS_MAX_QS - 1].OSQPtr = (OS_Q *)0;
  185.     OSQFreeList                  = &OSQTbl[0];
  186. }
  187. /*$PAGE*/
  188. /*
  189. *********************************************************************************************************
  190. *                                     PEND ON A QUEUE FOR A MESSAGE
  191. *
  192. * Description: This function waits for a message to be sent to a queue
  193. *
  194. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  195. *
  196. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  197. *                            wait for a message to arrive at the queue up to the amount of time 
  198. *                            specified by this argument.  If you specify 0, however, your task will wait 
  199. *                            forever at the specified queue or, until a message arrives.
  200. *
  201. *              err           is a pointer to where an error message will be deposited.  Possible error
  202. *                            messages are:
  203. *
  204. *                            OS_NO_ERR         The call was successful and your task received a message.
  205. *                            OS_TIMEOUT        A message was not received within the specified timeout
  206. *                            OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
  207. *                            OS_ERR_PEND_ISR    If you called this function from an ISR and the result
  208. *                                               would lead to a suspension.
  209. *
  210. * Returns    : != (void *)0  is a pointer to the message received
  211. *              == (void *)0  if no message was received or you didn't pass a pointer to a queue.
  212. *********************************************************************************************************
  213. */
  214. void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  215. {
  216.     void  *msg;
  217.     OS_Q  *pq;
  218.     OS_ENTER_CRITICAL();
  219.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
  220.         OS_EXIT_CRITICAL();
  221.         *err = OS_ERR_EVENT_TYPE;
  222.         return ((void *)0);
  223.     }
  224.     pq = pevent->OSEventPtr;                     /* Point at queue control block                       */
  225.     if (pq->OSQEntries != 0) {                   /* See if any messages in the queue                   */
  226.         msg = *pq->OSQOut++;                     /* Yes, extract oldest message from the queue         */
  227.         pq->OSQEntries--;                        /* Update the number of entries in the queue          */
  228.         if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
  229.             pq->OSQOut = pq->OSQStart;
  230.         }
  231.         OS_EXIT_CRITICAL();
  232.         *err = OS_NO_ERR;
  233.     } else if (OSIntNesting > 0) {               /* See if called from ISR ...                         */
  234.         OS_EXIT_CRITICAL();                      /* ... can't PEND from an ISR                         */
  235.         *err = OS_ERR_PEND_ISR;
  236.     } else {
  237.         OSTCBCur->OSTCBStat    |= OS_STAT_Q;     /* Task will have to pend for a message to be posted  */
  238.         OSTCBCur->OSTCBDly      = timeout;       /* Load timeout into TCB                              */
  239.         OSEventTaskWait(pevent);                 /* Suspend task until event or timeout occurs         */
  240.         OS_EXIT_CRITICAL();
  241.         OSSched();                               /* Find next highest priority task ready to run       */
  242.         OS_ENTER_CRITICAL();
  243.         if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) {/* Did we get a message?                         */
  244.             OSTCBCur->OSTCBMsg      = (void *)0;      /* Extract message from TCB (Put there by QPost) */
  245.             OSTCBCur->OSTCBStat     = OS_STAT_RDY;
  246.             OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;  /* No longer waiting for event                   */
  247.             OS_EXIT_CRITICAL();
  248.             *err                    = OS_NO_ERR;
  249.         } else if (OSTCBCur->OSTCBStat & OS_STAT_Q) { /* Timed out if status indicates pending on Q    */
  250.             OSEventTO(pevent);
  251.             OS_EXIT_CRITICAL();
  252.             msg                     = (void *)0;      /* No message received                           */
  253.             *err                    = OS_TIMEOUT;     /* Indicate a timeout occured                    */
  254.         } else {
  255.             msg = *pq->OSQOut++;                      /* Extract message from queue                    */
  256.             pq->OSQEntries--;                         /* Update the number of entries in the queue     */
  257.             if (pq->OSQOut == pq->OSQEnd) {           /* Wrap OUT pointer if we are at the end of Q    */
  258.                 pq->OSQOut = pq->OSQStart;
  259.             }
  260.             OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  261.             OS_EXIT_CRITICAL();
  262.             *err = OS_NO_ERR;
  263.         }
  264.     }                                                 
  265.     return (msg);                                     /* Return message received (or NULL)             */
  266. }
  267. /*$PAGE*/
  268. /*
  269. *********************************************************************************************************
  270. *                                        POST MESSAGE TO A QUEUE
  271. *
  272. * Description: This function sends a message to a queue
  273. *
  274. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  275. *
  276. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.  
  277. *
  278. * Returns    : OS_NO_ERR          The call was successful and the message was sent
  279. *              OS_Q_FULL          If the queue cannot accept any more messages because it is full.
  280. *              OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a queue.
  281. *********************************************************************************************************
  282. */
  283. INT8U OSQPost (OS_EVENT *pevent, void *msg)
  284. {
  285.     OS_Q   *pq;
  286.     OS_ENTER_CRITICAL();
  287.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  288.         OS_EXIT_CRITICAL();
  289.         return (OS_ERR_EVENT_TYPE);
  290.     }
  291.     if (pevent->OSEventGrp) {                         /* See if any task pending on queue              */
  292.         OSEventTaskRdy(pevent, msg, OS_STAT_Q);       /* Ready highest priority task waiting on event  */
  293.         OS_EXIT_CRITICAL();
  294.         OSSched();                                    /* Find highest priority task ready to run       */
  295.         return (OS_NO_ERR);
  296.     } else {
  297.         pq = pevent->OSEventPtr;                      /* Point to queue control block                  */
  298.         if (pq->OSQEntries >= pq->OSQSize) {          /* Make sure queue is not full                   */
  299.             OS_EXIT_CRITICAL();
  300.             return (OS_Q_FULL);
  301.         } else {
  302.             *pq->OSQIn++ = msg;                       /* Insert message into queue                     */
  303.             pq->OSQEntries++;                         /* Update the nbr of entries in the queue        */
  304.             if (pq->OSQIn == pq->OSQEnd) {            /* Wrap IN ptr if we are at end of queue         */
  305.                 pq->OSQIn = pq->OSQStart;
  306.             }
  307.             OS_EXIT_CRITICAL();
  308.         }
  309.         return (OS_NO_ERR);
  310.     }
  311. }
  312. /*$PAGE*/
  313. /*
  314. *********************************************************************************************************
  315. *                                   POST MESSAGE TO THE FRONT OF A QUEUE
  316. *
  317. * Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
  318. *              the front instead of the end of the queue.  Using OSQPostFront() allows you to send
  319. *              'priority' messages.  
  320. *
  321. * Arguments  : pevent        is a pointer to the event control block associated with the desired queue
  322. *
  323. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.  
  324. *
  325. * Returns    : OS_NO_ERR          The call was successful and the message was sent
  326. *              OS_Q_FULL          If the queue cannot accept any more messages because it is full.
  327. *              OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a queue.
  328. *********************************************************************************************************
  329. */
  330. INT8U OSQPostFront (OS_EVENT *pevent, void *msg)
  331. {
  332.     OS_Q   *pq;
  333.     OS_ENTER_CRITICAL();
  334.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
  335.         OS_EXIT_CRITICAL();
  336.         return (OS_ERR_EVENT_TYPE);
  337.     }
  338.     if (pevent->OSEventGrp) {                         /* See if any task pending on queue              */
  339.         OSEventTaskRdy(pevent, msg, OS_STAT_Q);       /* Ready highest priority task waiting on event  */
  340.         OS_EXIT_CRITICAL();
  341.         OSSched();                                    /* Find highest priority task ready to run       */
  342.         return (OS_NO_ERR);
  343.     } else {
  344.         pq = pevent->OSEventPtr;                      /* Point to queue control block                  */
  345.         if (pq->OSQEntries >= pq->OSQSize) {          /* Make sure queue is not full                   */
  346.             OS_EXIT_CRITICAL();
  347.             return (OS_Q_FULL);
  348.         } else {
  349.             if (pq->OSQOut == pq->OSQStart) {         /* Wrap OUT ptr if we are at the 1st queue entry */
  350.                 pq->OSQOut = pq->OSQEnd;
  351.             }
  352.             pq->OSQOut--;
  353.             *pq->OSQOut = msg;                        /* Insert message into queue                     */
  354.             pq->OSQEntries++;                         /* Update the nbr of entries in the queue        */
  355.             OS_EXIT_CRITICAL();
  356.         }
  357.         return (OS_NO_ERR);
  358.     }
  359. }
  360. /*$PAGE*/
  361. /*
  362. *********************************************************************************************************
  363. *                                        QUERY A MESSAGE QUEUE
  364. *
  365. * Description: This function obtains information about a message queue.
  366. *
  367. * Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
  368. *
  369. *              pdata         is a pointer to a structure that will contain information about the message
  370. *                            queue.
  371. *
  372. * Returns    : OS_NO_ERR          The call was successful and the message was sent
  373. *              OS_ERR_EVENT_TYPE  If you are attempting to obtain data from a non queue.
  374. *********************************************************************************************************
  375. */
  376. INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata)
  377. {
  378.     OS_Q   *pq;
  379.     INT8U   i;
  380.     INT8U  *psrc;
  381.     INT8U  *pdest;
  382.     
  383.     
  384.     OS_ENTER_CRITICAL();
  385.     if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
  386.         OS_EXIT_CRITICAL();
  387.         return (OS_ERR_EVENT_TYPE);
  388.     }
  389.     pdata->OSEventGrp = pevent->OSEventGrp;                /* Copy message mailbox wait list           */
  390.     psrc              = &pevent->OSEventTbl[0];
  391.     pdest             = &pdata->OSEventTbl[0];
  392.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  393.         *pdest++ = *psrc++;   
  394.     }
  395.     pq = (OS_Q *)pevent->OSEventPtr;
  396.     if (pq->OSQEntries > 0) {
  397.         pdata->OSMsg = pq->OSQOut;                         /* Get next message to return if available  */
  398.     } else {
  399.         pdata->OSMsg = (void *)0;
  400.     }
  401.     pdata->OSNMsgs = pq->OSQEntries;
  402.     pdata->OSQSize = pq->OSQSize;
  403.     OS_EXIT_CRITICAL();
  404.     return (OS_NO_ERR);
  405. }
  406. #endif