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

微处理器开发

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                       MESSAGE MAILBOX MANAGEMENT
  6. *
  7. *                          (c) Copyright 1992-2001, Jean J. Labrosse, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File : OS_MBOX.C
  11. * By   : Jean J. Labrosse
  12. *********************************************************************************************************
  13. */
  14. #ifndef  OS_MASTER_FILE
  15. #include "includes.h"
  16. #endif
  17. #if OS_MBOX_EN > 0
  18. /*
  19. *********************************************************************************************************
  20. *                                     ACCEPT MESSAGE FROM MAILBOX
  21. *
  22. * Description: This function checks the mailbox to see if a message is available.  Unlike OSMboxPend(),
  23. *              OSMboxAccept() 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 mailbox if one is available.  The mailbox is cleared
  28. *                            so the next time OSMboxAccept() is called, the mailbox will be empty.
  29. *              == (void *)0  if the mailbox is empty or,
  30. *                            if 'pevent' is a NULL pointer or,
  31. *                            if you didn't pass the proper event pointer.
  32. *********************************************************************************************************
  33. */
  34. #if OS_MBOX_ACCEPT_EN > 0
  35. void  *OSMboxAccept (OS_EVENT *pevent)
  36. {
  37. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  38.     OS_CPU_SR  cpu_sr;
  39. #endif    
  40.     void      *msg;
  41. #if OS_ARG_CHK_EN > 0
  42.     if (pevent == (OS_EVENT *)0) {                        /* Validate 'pevent'                         */
  43.         return ((void *)0);
  44.     }
  45.     if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {      /* Validate event block type                 */
  46.         return ((void *)0);
  47.     }
  48. #endif
  49.     OS_ENTER_CRITICAL();
  50.     msg                = pevent->OSEventPtr;
  51.     pevent->OSEventPtr = (void *)0;                       /* Clear the mailbox                         */
  52.     OS_EXIT_CRITICAL();
  53.     return (msg);                                         /* Return the message received (or NULL)     */
  54. }
  55. #endif
  56. /*$PAGE*/
  57. /*
  58. *********************************************************************************************************
  59. *                                        CREATE A MESSAGE MAILBOX
  60. *
  61. * Description: This function creates a message mailbox if free event control blocks are available.
  62. *
  63. * Arguments  : msg           is a pointer to a message that you wish to deposit in the mailbox.  If
  64. *                            you set this value to the NULL pointer (i.e. (void *)0) then the mailbox
  65. *                            will be considered empty.
  66. *
  67. * Returns    : != (OS_EVENT *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  68. *                                created mailbox
  69. *              == (OS_EVENT *)0  if no event control blocks were available
  70. *********************************************************************************************************
  71. */
  72. OS_EVENT  *OSMboxCreate (void *msg)
  73. {
  74. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  75.     OS_CPU_SR  cpu_sr;
  76. #endif    
  77.     OS_EVENT  *pevent;
  78.     if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
  79.         return ((OS_EVENT *)0);                  /* ... can't CREATE from an ISR                       */
  80.     }
  81.     OS_ENTER_CRITICAL();
  82.     pevent = OSEventFreeList;                    /* Get next free event control block                  */
  83.     if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
  84.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  85.     }
  86.     OS_EXIT_CRITICAL();
  87.     if (pevent != (OS_EVENT *)0) {
  88.         pevent->OSEventType = OS_EVENT_TYPE_MBOX;
  89.         pevent->OSEventPtr  = msg;               /* Deposit message in event control block             */
  90.         OS_EventWaitListInit(pevent);
  91.     }
  92.     return (pevent);                             /* Return pointer to event control block              */
  93. }
  94. /*$PAGE*/
  95. /*
  96. *********************************************************************************************************
  97. *                                         DELETE A MAIBOX
  98. *
  99. * Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
  100. *
  101. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  102. *                            mailbox.
  103. *
  104. *              opt           determines delete options as follows:
  105. *                            opt == OS_DEL_NO_PEND   Delete the mailbox ONLY if no task pending
  106. *                            opt == OS_DEL_ALWAYS    Deletes the mailbox even if tasks are waiting.
  107. *                                                    In this case, all the tasks pending will be readied.
  108. *
  109. *              err           is a pointer to an error code that can contain one of the following values:
  110. *                            OS_NO_ERR               The call was successful and the mailbox was deleted
  111. *                            OS_ERR_DEL_ISR          If you attempted to delete the mailbox from an ISR
  112. *                            OS_ERR_INVALID_OPT      An invalid option was specified
  113. *                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the mailbox
  114. *                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a mailbox
  115. *                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
  116. *
  117. * Returns    : pevent        upon error
  118. *              (OS_EVENT *)0 if the mailbox was successfully deleted.
  119. *
  120. * Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
  121. *                 the mailbox MUST check the return code of OSMboxPend().
  122. *              2) OSMboxAccept() callers will not know that the intended mailbox has been deleted unless
  123. *                 they check 'pevent' to see that it's a NULL pointer.
  124. *              3) This call can potentially disable interrupts for a long time.  The interrupt disable
  125. *                 time is directly proportional to the number of tasks waiting on the mailbox.
  126. *              4) Because ALL tasks pending on the mailbox will be readied, you MUST be careful in
  127. *                 applications where the mailbox is used for mutual exclusion because the resource(s)
  128. *                 will no longer be guarded by the mailbox.
  129. *********************************************************************************************************
  130. */
  131. #if OS_MBOX_DEL_EN > 0
  132. OS_EVENT  *OSMboxDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  133. {
  134. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  135.     OS_CPU_SR  cpu_sr;
  136. #endif    
  137.     BOOLEAN    tasks_waiting;
  138.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  139.         *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
  140.         return (pevent);
  141.     }
  142. #if OS_ARG_CHK_EN > 0
  143.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  144.         *err = OS_ERR_PEVENT_NULL;
  145.         return (pevent);
  146.     }
  147.     if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {       /* Validate event block type                */
  148.         *err = OS_ERR_EVENT_TYPE;
  149.         return (pevent);
  150.     }
  151. #endif
  152.     OS_ENTER_CRITICAL();
  153.     if (pevent->OSEventGrp != 0x00) {                      /* See if any tasks waiting on mailbox      */
  154.         tasks_waiting = TRUE;                              /* Yes                                      */
  155.     } else {
  156.         tasks_waiting = FALSE;                             /* No                                       */
  157.     }
  158.     switch (opt) {
  159.         case OS_DEL_NO_PEND:                               /* Delete mailbox only if no task waiting   */
  160.              if (tasks_waiting == FALSE) {
  161.                  pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  162.                  pevent->OSEventPtr  = OSEventFreeList;    /* Return Event Control Block to free list  */
  163.                  OSEventFreeList     = pevent;             /* Get next free event control block        */
  164.                  OS_EXIT_CRITICAL();
  165.                  *err = OS_NO_ERR;
  166.                  return ((OS_EVENT *)0);                   /* Mailbox has been deleted                 */
  167.              } else {
  168.                  OS_EXIT_CRITICAL();
  169.                  *err = OS_ERR_TASK_WAITING;
  170.                  return (pevent);
  171.              }
  172.         case OS_DEL_ALWAYS:                                /* Always delete the mailbox                */
  173.              while (pevent->OSEventGrp != 0x00) {          /* Ready ALL tasks waiting for mailbox      */
  174.                  OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX);
  175.              }
  176.              pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  177.              pevent->OSEventPtr  = OSEventFreeList;        /* Return Event Control Block to free list  */
  178.              OSEventFreeList     = pevent;                 /* Get next free event control block        */
  179.              OS_EXIT_CRITICAL();
  180.              if (tasks_waiting == TRUE) {                  /* Reschedule only if task(s) were waiting  */
  181.                  OS_Sched();                               /* Find highest priority task ready to run  */
  182.              }
  183.              *err = OS_NO_ERR;
  184.              return ((OS_EVENT *)0);                       /* Mailbox has been deleted                 */
  185.         default:
  186.              OS_EXIT_CRITICAL();
  187.              *err = OS_ERR_INVALID_OPT;
  188.              return (pevent);
  189.     }
  190. }
  191. #endif
  192. /*$PAGE*/
  193. /*
  194. *********************************************************************************************************
  195. *                                      PEND ON MAILBOX FOR A MESSAGE
  196. *
  197. * Description: This function waits for a message to be sent to a mailbox
  198. *
  199. * Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
  200. *
  201. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  202. *                            wait for a message to arrive at the mailbox up to the amount of time
  203. *                            specified by this argument.  If you specify 0, however, your task will wait
  204. *                            forever at the specified mailbox or, until a message arrives.
  205. *
  206. *              err           is a pointer to where an error message will be deposited.  Possible error
  207. *                            messages are:
  208. *
  209. *                            OS_NO_ERR           The call was successful and your task received a
  210. *                                                message.
  211. *                            OS_TIMEOUT          A message was not received within the specified timeout
  212. *                            OS_ERR_EVENT_TYPE   Invalid event type
  213. *                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
  214. *                                                would lead to a suspension.
  215. *                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  216. *
  217. * Returns    : != (void *)0  is a pointer to the message received
  218. *              == (void *)0  if no message was received or,
  219. *                            if 'pevent' is a NULL pointer or,
  220. *                            if you didn't pass the proper pointer to the event control block.
  221. *********************************************************************************************************
  222. */
  223. void  *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  224. {
  225. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  226.     OS_CPU_SR  cpu_sr;
  227. #endif    
  228.     void      *msg;
  229.     if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
  230.         *err = OS_ERR_PEND_ISR;                       /* ... can't PEND from an ISR                    */
  231.         return ((void *)0);
  232.     }
  233. #if OS_ARG_CHK_EN > 0
  234.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  235.         *err = OS_ERR_PEVENT_NULL;
  236.         return ((void *)0);
  237.     }
  238.     if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
  239.         *err = OS_ERR_EVENT_TYPE;
  240.         return ((void *)0);
  241.     }
  242. #endif
  243.     OS_ENTER_CRITICAL();
  244.     msg = pevent->OSEventPtr;
  245.     if (msg != (void *)0) {                           /* See if there is already a message             */
  246.         pevent->OSEventPtr = (void *)0;               /* Clear the mailbox                             */
  247.         OS_EXIT_CRITICAL();
  248.         *err = OS_NO_ERR;
  249.         return (msg);                                 /* Return the message received (or NULL)         */
  250.     }
  251.     OSTCBCur->OSTCBStat |= OS_STAT_MBOX;              /* Message not available, task will pend         */
  252.     OSTCBCur->OSTCBDly   = timeout;                   /* Load timeout in TCB                           */
  253.     OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
  254.     OS_EXIT_CRITICAL();
  255.     OS_Sched();                                       /* Find next highest priority task ready to run  */
  256.     OS_ENTER_CRITICAL();
  257.     msg = OSTCBCur->OSTCBMsg;
  258.     if (msg != (void *)0) {                           /* See if we were given the message              */
  259.         OSTCBCur->OSTCBMsg      = (void *)0;          /* Yes, clear message received                   */
  260.         OSTCBCur->OSTCBStat     = OS_STAT_RDY;
  261.         OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;      /* No longer waiting for event                   */
  262.         OS_EXIT_CRITICAL();
  263.         *err                    = OS_NO_ERR;
  264.         return (msg);                                 /* Return the message received                   */
  265.     }
  266.     OS_EventTO(pevent);                               /* Timed out, Make task ready                    */
  267.     OS_EXIT_CRITICAL();
  268.     *err = OS_TIMEOUT;                                /* Indicate that a timeout occured               */
  269.     return ((void *)0);                               /* Return a NULL message                         */
  270. }
  271. /*$PAGE*/
  272. /*
  273. *********************************************************************************************************
  274. *                                       POST MESSAGE TO A MAILBOX
  275. *
  276. * Description: This function sends a message to a mailbox
  277. *
  278. * Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
  279. *
  280. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
  281. *
  282. * Returns    : OS_NO_ERR            The call was successful and the message was sent
  283. *              OS_MBOX_FULL         If the mailbox already contains a message.  You can can only send one
  284. *                                   message at a time and thus, the message MUST be consumed before you
  285. *                                   are allowed to send another one.
  286. *              OS_ERR_EVENT_TYPE    If you are attempting to post to a non mailbox.
  287. *              OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer
  288. *              OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
  289. *********************************************************************************************************
  290. */
  291. #if OS_MBOX_POST_EN > 0
  292. INT8U  OSMboxPost (OS_EVENT *pevent, void *msg)
  293. {
  294. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  295.     OS_CPU_SR  cpu_sr;
  296. #endif    
  297.     
  298.     
  299. #if OS_ARG_CHK_EN > 0
  300.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  301.         return (OS_ERR_PEVENT_NULL);
  302.     }
  303.     if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
  304.         return (OS_ERR_POST_NULL_PTR);
  305.     }
  306.     if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
  307.         return (OS_ERR_EVENT_TYPE);
  308.     }
  309. #endif
  310.     OS_ENTER_CRITICAL();
  311.     if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on mailbox            */
  312.         OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);   /* Ready highest priority task waiting on event  */
  313.         OS_EXIT_CRITICAL();
  314.         OS_Sched();                                   /* Find highest priority task ready to run       */
  315.         return (OS_NO_ERR);
  316.     }
  317.     if (pevent->OSEventPtr != (void *)0) {            /* Make sure mailbox doesn't already have a msg  */
  318.         OS_EXIT_CRITICAL();
  319.         return (OS_MBOX_FULL);
  320.     }
  321.     pevent->OSEventPtr = msg;                         /* Place message in mailbox                      */
  322.     OS_EXIT_CRITICAL();
  323.     return (OS_NO_ERR);
  324. }
  325. #endif
  326. /*$PAGE*/
  327. /*
  328. *********************************************************************************************************
  329. *                                       POST MESSAGE TO A MAILBOX
  330. *
  331. * Description: This function sends a message to a mailbox
  332. *
  333. * Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
  334. *
  335. *              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
  336. *
  337. *              opt           determines the type of POST performed:
  338. *                            OS_POST_OPT_NONE         POST to a single waiting task 
  339. *                                                     (Identical to OSMboxPost())
  340. *                            OS_POST_OPT_BROADCAST    POST to ALL tasks that are waiting on the mailbox
  341. *
  342. * Returns    : OS_NO_ERR            The call was successful and the message was sent
  343. *              OS_MBOX_FULL         If the mailbox already contains a message.  You can can only send one
  344. *                                   message at a time and thus, the message MUST be consumed before you
  345. *                                   are allowed to send another one.
  346. *              OS_ERR_EVENT_TYPE    If you are attempting to post to a non mailbox.
  347. *              OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer
  348. *              OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
  349. *
  350. * Warning    : Interrupts can be disabled for a long time if you do a 'broadcast'.  In fact, the 
  351. *              interrupt disable time is proportional to the number of tasks waiting on the mailbox.
  352. *********************************************************************************************************
  353. */
  354. #if OS_MBOX_POST_OPT_EN > 0
  355. INT8U  OSMboxPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
  356. {
  357. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  358.     OS_CPU_SR  cpu_sr;
  359. #endif    
  360.     
  361.     
  362. #if OS_ARG_CHK_EN > 0
  363.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  364.         return (OS_ERR_PEVENT_NULL);
  365.     }
  366.     if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
  367.         return (OS_ERR_POST_NULL_PTR);
  368.     }
  369.     if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
  370.         return (OS_ERR_EVENT_TYPE);
  371.     }
  372. #endif
  373.     OS_ENTER_CRITICAL();
  374.     if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on mailbox            */
  375.         if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* Do we need to post msg to ALL waiting tasks ? */
  376.             while (pevent->OSEventGrp != 0x00) {      /* Yes, Post to ALL tasks waiting on mailbox     */           
  377.                 OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);    
  378.             }
  379.         } else {
  380.             OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);    /* No,  Post to HPT waiting on mbox         */
  381.         }
  382.         OS_EXIT_CRITICAL();
  383.         OS_Sched();                                   /* Find highest priority task ready to run       */
  384.         return (OS_NO_ERR);
  385.     }
  386.     if (pevent->OSEventPtr != (void *)0) {            /* Make sure mailbox doesn't already have a msg  */
  387.         OS_EXIT_CRITICAL();
  388.         return (OS_MBOX_FULL);
  389.     }
  390.     pevent->OSEventPtr = msg;                         /* Place message in mailbox                      */
  391.     OS_EXIT_CRITICAL();
  392.     return (OS_NO_ERR);
  393. }
  394. #endif
  395. /*$PAGE*/
  396. /*
  397. *********************************************************************************************************
  398. *                                        QUERY A MESSAGE MAILBOX
  399. *
  400. * Description: This function obtains information about a message mailbox.
  401. *
  402. * Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
  403. *
  404. *              pdata         is a pointer to a structure that will contain information about the message
  405. *                            mailbox.
  406. *
  407. * Returns    : OS_NO_ERR           The call was successful and the message was sent
  408. *              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non mailbox.
  409. *              OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
  410. *********************************************************************************************************
  411. */
  412. #if OS_MBOX_QUERY_EN > 0
  413. INT8U  OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata)
  414. {
  415. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  416.     OS_CPU_SR  cpu_sr;
  417. #endif    
  418.     INT8U     *psrc;
  419.     INT8U     *pdest;
  420. #if OS_ARG_CHK_EN > 0
  421.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  422.         return (OS_ERR_PEVENT_NULL);
  423.     }
  424.     if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {       /* Validate event block type                */
  425.         return (OS_ERR_EVENT_TYPE);
  426.     }
  427. #endif
  428.     OS_ENTER_CRITICAL();
  429.     pdata->OSEventGrp = pevent->OSEventGrp;                /* Copy message mailbox wait list           */
  430.     psrc              = &pevent->OSEventTbl[0];
  431.     pdest             = &pdata->OSEventTbl[0];
  432. #if OS_EVENT_TBL_SIZE > 0
  433.     *pdest++          = *psrc++;
  434. #endif
  435. #if OS_EVENT_TBL_SIZE > 1
  436.     *pdest++          = *psrc++;
  437. #endif
  438. #if OS_EVENT_TBL_SIZE > 2
  439.     *pdest++          = *psrc++;
  440. #endif
  441. #if OS_EVENT_TBL_SIZE > 3
  442.     *pdest++          = *psrc++;
  443. #endif
  444. #if OS_EVENT_TBL_SIZE > 4
  445.     *pdest++          = *psrc++;
  446. #endif
  447. #if OS_EVENT_TBL_SIZE > 5
  448.     *pdest++          = *psrc++;
  449. #endif
  450. #if OS_EVENT_TBL_SIZE > 6
  451.     *pdest++          = *psrc++;
  452. #endif
  453. #if OS_EVENT_TBL_SIZE > 7
  454.     *pdest            = *psrc;
  455. #endif
  456.     pdata->OSMsg = pevent->OSEventPtr;                     /* Get message from mailbox                 */
  457.     OS_EXIT_CRITICAL();
  458.     return (OS_NO_ERR);
  459. }
  460. #endif                                                     /* OS_MBOX_QUERY_EN                         */
  461. #endif                                                     /* OS_MBOX_EN                               */