os_core.c
上传用户:ht5068443
上传日期:2016-07-26
资源大小:802k
文件大小:85k
源码类别:

MacOS编程

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                             CORE FUNCTIONS
  6. *
  7. *                              (c) Copyright 1992-2009, Micrium, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File    : OS_CORE.C
  11. * By      : Jean J. Labrosse
  12. * Version : V2.88
  13. *
  14. * LICENSING TERMS:
  15. * ---------------
  16. *   uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.  
  17. * If you plan on using  uC/OS-II  in a commercial product you need to contact Micri祄 to properly license 
  18. * its use in your product. We provide ALL the source code for your convenience and to help you experience 
  19. * uC/OS-II.   The fact that the  source is provided does  NOT  mean that you can use it without  paying a 
  20. * licensing fee.
  21. *********************************************************************************************************
  22. */
  23. #ifndef  OS_MASTER_FILE
  24. #define  OS_GLOBALS
  25. #include <ucos_ii.h>
  26. #endif
  27. /*
  28. *********************************************************************************************************
  29. *                                       PRIORITY RESOLUTION TABLE
  30. *
  31. * Note: Index into table is bit pattern to resolve highest priority
  32. *       Indexed value corresponds to highest priority bit position (i.e. 0..7)
  33. *********************************************************************************************************
  34. */
  35. INT8U  const  OSUnMapTbl[256] = {
  36.     0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x00 to 0x0F                             */
  37.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x10 to 0x1F                             */
  38.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x20 to 0x2F                             */
  39.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x30 to 0x3F                             */
  40.     6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x40 to 0x4F                             */
  41.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x50 to 0x5F                             */
  42.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x60 to 0x6F                             */
  43.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x70 to 0x7F                             */
  44.     7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x80 to 0x8F                             */
  45.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x90 to 0x9F                             */
  46.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xA0 to 0xAF                             */
  47.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xB0 to 0xBF                             */
  48.     6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xC0 to 0xCF                             */
  49.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xD0 to 0xDF                             */
  50.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xE0 to 0xEF                             */
  51.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0        /* 0xF0 to 0xFF                             */
  52. };
  53. /*$PAGE*/
  54. /*
  55. *********************************************************************************************************
  56. *                                       FUNCTION PROTOTYPES
  57. *********************************************************************************************************
  58. */
  59. static  void  OS_InitEventList(void);
  60. static  void  OS_InitMisc(void);
  61. static  void  OS_InitRdyList(void);
  62. static  void  OS_InitTaskIdle(void);
  63. #if OS_TASK_STAT_EN > 0
  64. static  void  OS_InitTaskStat(void);
  65. #endif
  66. static  void  OS_InitTCBList(void);
  67. static  void  OS_SchedNew(void);
  68. /*$PAGE*/
  69. /*
  70. *********************************************************************************************************
  71. *                         GET THE NAME OF A SEMAPHORE, MUTEX, MAILBOX or QUEUE
  72. *
  73. * Description: This function is used to obtain the name assigned to a semaphore, mutex, mailbox or queue.
  74. *
  75. * Arguments  : pevent    is a pointer to the event group.  'pevent' can point either to a semaphore,
  76. *                        a mutex, a mailbox or a queue.  Where this function is concerned, the actual
  77. *                        type is irrelevant.
  78. *
  79. *              pname     is a pointer to an ASCII string that will receive the name of the semaphore,
  80. *                        mutex, mailbox or queue.  
  81. *
  82. *              perr      is a pointer to an error code that can contain one of the following values:
  83. *
  84. *                        OS_ERR_NONE                if the name was copied to 'pname'
  85. *                        OS_ERR_EVENT_TYPE          if 'pevent' is not pointing to the proper event
  86. *                                                   control block type.
  87. *                        OS_ERR_PNAME_NULL          You passed a NULL pointer for 'pname'
  88. *                        OS_ERR_PEVENT_NULL         if you passed a NULL pointer for 'pevent'
  89. *                        OS_ERR_NAME_GET_ISR        if you are trying to call this function from an ISR
  90. *
  91. * Returns    : The length of the string or 0 if the 'pevent' is a NULL pointer.
  92. *********************************************************************************************************
  93. */
  94. #if (OS_EVENT_EN) && (OS_EVENT_NAME_EN > 0)
  95. INT8U  OSEventNameGet (OS_EVENT  *pevent, 
  96.                        INT8U     *pname, 
  97.                        INT8U     *perr)
  98. {
  99.     INT8U      len;
  100. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  101.     OS_CPU_SR  cpu_sr = 0;
  102. #endif
  103. #if OS_ARG_CHK_EN > 0
  104.     if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
  105.         return (0);
  106.     }
  107.     if (pevent == (OS_EVENT *)0) {               /* Is 'pevent' a NULL pointer?                        */
  108.         *perr = OS_ERR_PEVENT_NULL;
  109.         return (0);
  110.     }
  111.     if (pname == (INT8U *)0) {                   /* Is 'pname' a NULL pointer?                         */
  112.         *perr = OS_ERR_PNAME_NULL;
  113.         return (0);
  114.     }
  115. #endif
  116.     if (OSIntNesting > 0) {                      /* See if trying to call from an ISR                  */
  117.         *perr  = OS_ERR_NAME_GET_ISR;
  118.         return (0);
  119.     }
  120.     switch (pevent->OSEventType) {
  121.         case OS_EVENT_TYPE_SEM:
  122.         case OS_EVENT_TYPE_MUTEX:
  123.         case OS_EVENT_TYPE_MBOX:
  124.         case OS_EVENT_TYPE_Q:
  125.              break;
  126.         default:
  127.              *perr = OS_ERR_EVENT_TYPE;
  128.              return (0);
  129.     }
  130.     OS_ENTER_CRITICAL();
  131.     pname = pevent->OSEventName;
  132.     len   = OS_StrLen(pname);
  133.     OS_EXIT_CRITICAL();
  134.     *perr = OS_ERR_NONE;
  135.     return (len);
  136. }
  137. #endif
  138. /*$PAGE*/
  139. /*
  140. *********************************************************************************************************
  141. *                         ASSIGN A NAME TO A SEMAPHORE, MUTEX, MAILBOX or QUEUE
  142. *
  143. * Description: This function assigns a name to a semaphore, mutex, mailbox or queue.
  144. *
  145. * Arguments  : pevent    is a pointer to the event group.  'pevent' can point either to a semaphore,
  146. *                        a mutex, a mailbox or a queue.  Where this function is concerned, it doesn't
  147. *                        matter the actual type.
  148. *
  149. *              pname     is a pointer to an ASCII string that will be used as the name of the semaphore,
  150. *                        mutex, mailbox or queue.  
  151. *
  152. *              perr      is a pointer to an error code that can contain one of the following values:
  153. *
  154. *                        OS_ERR_NONE                if the requested task is resumed
  155. *                        OS_ERR_EVENT_TYPE          if 'pevent' is not pointing to the proper event
  156. *                                                   control block type.
  157. *                        OS_ERR_PNAME_NULL          You passed a NULL pointer for 'pname'
  158. *                        OS_ERR_PEVENT_NULL         if you passed a NULL pointer for 'pevent'
  159. *                        OS_ERR_NAME_SET_ISR        if you called this function from an ISR
  160. *
  161. * Returns    : None
  162. *********************************************************************************************************
  163. */
  164. #if (OS_EVENT_EN) && (OS_EVENT_NAME_EN > 0)
  165. void  OSEventNameSet (OS_EVENT  *pevent, 
  166.                       INT8U     *pname, 
  167.                       INT8U     *perr)
  168. {
  169. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  170.     OS_CPU_SR  cpu_sr = 0;
  171. #endif
  172. #if OS_ARG_CHK_EN > 0
  173.     if (perr == (INT8U *)0) {                    /* Validate 'perr'                                    */
  174.         return;
  175.     }
  176.     if (pevent == (OS_EVENT *)0) {               /* Is 'pevent' a NULL pointer?                        */
  177.         *perr = OS_ERR_PEVENT_NULL;
  178.         return;
  179.     }
  180.     if (pname == (INT8U *)0) {                   /* Is 'pname' a NULL pointer?                         */
  181.         *perr = OS_ERR_PNAME_NULL;
  182.         return;
  183.     }
  184. #endif
  185.     if (OSIntNesting > 0) {                      /* See if trying to call from an ISR                  */
  186.         *perr = OS_ERR_NAME_SET_ISR;
  187.         return;
  188.     }
  189.     switch (pevent->OSEventType) {
  190.         case OS_EVENT_TYPE_SEM:
  191.         case OS_EVENT_TYPE_MUTEX:
  192.         case OS_EVENT_TYPE_MBOX:
  193.         case OS_EVENT_TYPE_Q:
  194.              break;
  195.         default:
  196.              *perr = OS_ERR_EVENT_TYPE;
  197.              return;
  198.     }
  199.     OS_ENTER_CRITICAL();
  200.     pevent->OSEventName = pname;
  201.     OS_EXIT_CRITICAL();
  202.     *perr = OS_ERR_NONE;
  203. }
  204. #endif
  205. /*$PAGE*/
  206. /*
  207. *********************************************************************************************************
  208. *                                      PEND ON MULTIPLE EVENTS
  209. *
  210. * Description: This function waits for multiple events.  If multiple events are ready at the start of the
  211. *              pend call, then all available events are returned as ready.  If the task must pend on the
  212. *              multiple events, then only the first posted or aborted event is returned as ready.
  213. *
  214. * Arguments  : pevents_pend  is a pointer to a NULL-terminated array of event control blocks to wait for.
  215. *
  216. *              pevents_rdy   is a pointer to an array to return which event control blocks are available
  217. *                            or ready.  The size of the array MUST be greater than or equal to the size
  218. *                            of the 'pevents_pend' array, including terminating NULL.
  219. *
  220. *              pmsgs_rdy     is a pointer to an array to return messages from any available message-type
  221. *                            events.  The size of the array MUST be greater than or equal to the size of
  222. *                            the 'pevents_pend' array, excluding the terminating NULL.  Since NULL
  223. *                            messages are valid messages, this array cannot be NULL-terminated.  Instead,
  224. *                            every available message-type event returns its messages in the 'pmsgs_rdy'
  225. *                            array at the same index as the event is returned in the 'pevents_rdy' array.
  226. *                            All other 'pmsgs_rdy' array indices are filled with NULL messages.
  227. *
  228. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  229. *                            wait for the resources up to the amount of time specified by this argument.
  230. *                            If you specify 0, however, your task will wait forever for the specified
  231. *                            events or, until the resources becomes available (or the events occur).
  232. *
  233. *              perr          is a pointer to where an error message will be deposited.  Possible error
  234. *                            messages are:
  235. *
  236. *                            OS_ERR_NONE         The call was successful and your task owns the resources
  237. *                                                or, the events you are waiting for occurred; check the
  238. *                                                'pevents_rdy' array for which events are available.
  239. *                            OS_ERR_PEND_ABORT   The wait on the events was aborted; check the
  240. *                                                'pevents_rdy' array for which events were aborted.
  241. *                            OS_ERR_TIMEOUT      The events were not received within the specified
  242. *                                                'timeout'.
  243. *                            OS_ERR_PEVENT_NULL  If 'pevents_pend', 'pevents_rdy', or 'pmsgs_rdy' is a 
  244. *                                                NULL pointer.
  245. *                            OS_ERR_EVENT_TYPE   If you didn't pass a pointer to an array of semaphores, 
  246. *                                                mailboxes, and/or queues.
  247. *                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
  248. *                                                would lead to a suspension.
  249. *                            OS_ERR_PEND_LOCKED  If you called this function when the scheduler is locked.
  250. *
  251. * Returns    : >  0          the number of events returned as ready or aborted.
  252. *              == 0          if no events are returned as ready because of timeout or upon error.
  253. *
  254. * Notes      : 1) a. Validate 'pevents_pend' array as valid OS_EVENTs : 
  255. *
  256. *                        semaphores, mailboxes, queues
  257. *
  258. *                 b. Return ALL available events and messages, if any
  259. *
  260. *                 c. Add    current task priority as pending to   each events's wait list
  261. *                      Performed in OS_EventTaskWaitMulti()
  262. *
  263. *                 d. Wait on any of multiple events
  264. *
  265. *                 e. Remove current task priority as pending from each events's wait list
  266. *                      Performed in OS_EventTaskRdy(), if events posted or aborted
  267. *
  268. *                 f. Return any event posted or aborted, if any
  269. *                      else
  270. *                    Return timeout
  271. *
  272. *              2) 'pevents_rdy' initialized to NULL PRIOR to all other validation or function handling in 
  273. *                 case of any error(s).
  274. *********************************************************************************************************
  275. */
  276. /*$PAGE*/
  277. #if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0))
  278. INT16U  OSEventPendMulti (OS_EVENT  **pevents_pend, 
  279.                           OS_EVENT  **pevents_rdy, 
  280.                           void      **pmsgs_rdy, 
  281.                           INT32U      timeout, 
  282.                           INT8U      *perr)
  283. {
  284.     OS_EVENT  **pevents;
  285.     OS_EVENT   *pevent;
  286. #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
  287.     OS_Q       *pq;
  288. #endif
  289.     BOOLEAN     events_rdy;
  290.     INT16U      events_rdy_nbr;
  291.     INT8U       events_stat;
  292. #if (OS_CRITICAL_METHOD == 3)                           /* Allocate storage for CPU status register    */
  293.     OS_CPU_SR   cpu_sr = 0;
  294. #endif
  295. #if (OS_ARG_CHK_EN > 0)
  296.     if (perr == (INT8U *)0) {                           /* Validate 'perr'                             */
  297.         return (0);
  298.     }
  299.     if (pevents_pend == (OS_EVENT **)0) {               /* Validate 'pevents_pend'                     */
  300.        *perr =  OS_ERR_PEVENT_NULL;
  301.         return (0);
  302.     }
  303.     if (pevents_rdy  == (OS_EVENT **)0) {               /* Validate 'pevents_rdy'                      */
  304.        *perr =  OS_ERR_PEVENT_NULL;
  305.         return (0);
  306.     }
  307.     if (pmsgs_rdy == (void **)0) {                      /* Validate 'pmsgs_rdy'                        */
  308.        *perr =  OS_ERR_PEVENT_NULL;
  309.         return (0);
  310.     }
  311. #endif
  312.    *pevents_rdy = (OS_EVENT *)0;                        /* Init array to NULL in case of errors        */
  313.     pevents     =  pevents_pend;
  314.     pevent      = *pevents;
  315.     while  (pevent != (OS_EVENT *)0) {
  316.         switch (pevent->OSEventType) {                  /* Validate event block types                  */
  317. #if (OS_SEM_EN  > 0)
  318.             case OS_EVENT_TYPE_SEM:
  319.                  break;
  320. #endif
  321. #if (OS_MBOX_EN > 0)
  322.             case OS_EVENT_TYPE_MBOX:
  323.                  break;
  324. #endif
  325. #if ((OS_Q_EN   > 0) && (OS_MAX_QS > 0))
  326.             case OS_EVENT_TYPE_Q:
  327.                  break;
  328. #endif
  329.             case OS_EVENT_TYPE_MUTEX:                                            
  330.             case OS_EVENT_TYPE_FLAG:
  331.             default:           
  332.                 *perr = OS_ERR_EVENT_TYPE;
  333.                  return (0);
  334.         }
  335.         pevents++;
  336.         pevent = *pevents;
  337.     }
  338.     if (OSIntNesting  > 0) {                            /* See if called from ISR ...                  */
  339.        *perr =  OS_ERR_PEND_ISR;                        /* ... can't PEND from an ISR                  */
  340.         return (0);
  341.     }
  342.     if (OSLockNesting > 0) {                            /* See if called with scheduler locked ...     */
  343.        *perr =  OS_ERR_PEND_LOCKED;                     /* ... can't PEND when locked                  */
  344.         return (0);
  345.     }
  346. /*$PAGE*/
  347.     OS_ENTER_CRITICAL();
  348.     events_rdy     =  OS_FALSE;
  349.     events_rdy_nbr =  0;
  350.     events_stat    =  OS_STAT_RDY;
  351.     pevents        =  pevents_pend;
  352.     pevent         = *pevents;
  353.     while (pevent != (OS_EVENT *)0) {                   /* See if any events already available         */
  354.         switch (pevent->OSEventType) {
  355. #if (OS_SEM_EN > 0)
  356.             case OS_EVENT_TYPE_SEM:
  357.                  if (pevent->OSEventCnt > 0) {          /* If semaphore count > 0, resource available; */
  358.                      pevent->OSEventCnt--;              /* ... decrement semaphore,                ... */
  359.                     *pevents_rdy++ =  pevent;           /* ... and return available semaphore event    */
  360.                       events_rdy   =  OS_TRUE;
  361.                     *pmsgs_rdy++   = (void *)0;         /* NO message returned  for semaphores         */
  362.                       events_rdy_nbr++;
  363.                  } else {
  364.                       events_stat |=  OS_STAT_SEM;      /* Configure multi-pend for semaphore events   */
  365.                  }
  366.                  break;
  367. #endif
  368. #if (OS_MBOX_EN > 0)
  369.             case OS_EVENT_TYPE_MBOX:
  370.                  if (pevent->OSEventPtr != (void *)0) { /* If mailbox NOT empty;                   ... */
  371.                                                         /* ... return available message,           ... */
  372.                     *pmsgs_rdy++         = (void *)pevent->OSEventPtr;
  373.                      pevent->OSEventPtr  = (void *)0;
  374.                     *pevents_rdy++       =  pevent;     /* ... and return available mailbox event      */
  375.                       events_rdy         =  OS_TRUE;
  376.                       events_rdy_nbr++;
  377.                  } else {
  378.                       events_stat |= OS_STAT_MBOX;      /* Configure multi-pend for mailbox events     */
  379.                  }
  380.                  break;
  381. #endif
  382. #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
  383.             case OS_EVENT_TYPE_Q:
  384.                  pq = (OS_Q *)pevent->OSEventPtr;
  385.                  if (pq->OSQEntries > 0) {              /* If queue NOT empty;                     ... */
  386.                                                         /* ... return available message,           ... */
  387.                     *pmsgs_rdy++ = (void *)*pq->OSQOut++;
  388.                      if (pq->OSQOut == pq->OSQEnd) {    /* If OUT ptr at queue end, ...                */
  389.                          pq->OSQOut  = pq->OSQStart;    /* ... wrap   to queue start                   */
  390.                      }
  391.                      pq->OSQEntries--;                  /* Update number of queue entries              */
  392.                     *pevents_rdy++ = pevent;            /* ... and return available queue event        */
  393.                       events_rdy   = OS_TRUE;
  394.                       events_rdy_nbr++;
  395.                  } else {
  396.                       events_stat |= OS_STAT_Q;         /* Configure multi-pend for queue events       */
  397.                  }
  398.                  break;
  399. #endif
  400.             case OS_EVENT_TYPE_MUTEX:                                            
  401.             case OS_EVENT_TYPE_FLAG:
  402.             default:           
  403.                  OS_EXIT_CRITICAL();
  404.                 *pevents_rdy = (OS_EVENT *)0;           /* NULL terminate return event array           */
  405.                 *perr        =  OS_ERR_EVENT_TYPE;
  406.                  return (events_rdy_nbr);
  407.         }
  408.         pevents++;
  409.         pevent = *pevents;
  410.     }
  411.     if ( events_rdy == OS_TRUE) {                       /* Return any events already available         */
  412.        *pevents_rdy = (OS_EVENT *)0;                    /* NULL terminate return event array           */
  413.         OS_EXIT_CRITICAL();
  414.        *perr        =  OS_ERR_NONE;
  415.         return (events_rdy_nbr);
  416.     }
  417. /*$PAGE*/
  418.                                                         /* Otherwise, must wait until any event occurs */
  419.     OSTCBCur->OSTCBStat     |= events_stat  |           /* Resource not available, ...                 */
  420.                                OS_STAT_MULTI;           /* ... pend on multiple events                 */
  421.     OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
  422.     OSTCBCur->OSTCBDly       = timeout;                 /* Store pend timeout in TCB                   */
  423.     OS_EventTaskWaitMulti(pevents_pend);                /* Suspend task until events or timeout occurs */
  424.     OS_EXIT_CRITICAL();
  425.     OS_Sched();                                         /* Find next highest priority task ready       */
  426.     OS_ENTER_CRITICAL();
  427.     switch (OSTCBCur->OSTCBStatPend) {                  /* Handle event posted, aborted, or timed-out  */
  428.         case OS_STAT_PEND_OK:
  429.         case OS_STAT_PEND_ABORT:
  430.              pevent = OSTCBCur->OSTCBEventPtr;
  431.              if (pevent != (OS_EVENT *)0) {             /* If task event ptr != NULL, ...              */
  432.                 *pevents_rdy++ =  pevent;               /* ... return available event ...              */
  433.                 *pevents_rdy   = (OS_EVENT *)0;         /* ... & NULL terminate return event array     */
  434.                   events_rdy_nbr++;
  435.              } else {                                   /* Else NO event available, handle as timeout  */
  436.                  OSTCBCur->OSTCBStatPend = OS_STAT_PEND_TO;
  437.                  OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
  438.              }
  439.  break;
  440.         case OS_STAT_PEND_TO:                           /* If events timed out, ...                    */
  441.         default:                                        /* ... remove task from events' wait lists     */
  442.              OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
  443.              break;
  444.     }
  445.     switch (OSTCBCur->OSTCBStatPend) {
  446.         case OS_STAT_PEND_OK:
  447.              switch (pevent->OSEventType) {             /* Return event's message                      */
  448. #if (OS_SEM_EN > 0)
  449.                  case OS_EVENT_TYPE_SEM:
  450.                      *pmsgs_rdy++ = (void *)0;          /* NO message returned for semaphores          */
  451.                       break;
  452. #endif
  453. #if ((OS_MBOX_EN > 0) ||                 
  454.     ((OS_Q_EN    > 0) && (OS_MAX_QS > 0)))
  455.                  case OS_EVENT_TYPE_MBOX:
  456.                  case OS_EVENT_TYPE_Q:
  457.                      *pmsgs_rdy++ = (void *)OSTCBCur->OSTCBMsg;     /* Return received message         */
  458.                       break;
  459. #endif
  460.                  case OS_EVENT_TYPE_MUTEX:                                       
  461.                  case OS_EVENT_TYPE_FLAG:
  462.                  default:           
  463.                       OS_EXIT_CRITICAL();
  464.                      *pevents_rdy = (OS_EVENT *)0;      /* NULL terminate return event array           */
  465.                      *perr        =  OS_ERR_EVENT_TYPE;
  466.                       return (events_rdy_nbr);
  467.              }
  468.             *perr = OS_ERR_NONE;
  469.              break;
  470.         case OS_STAT_PEND_ABORT:
  471.             *pmsgs_rdy++ = (void *)0;                   /* NO message returned for abort               */
  472.             *perr        =  OS_ERR_PEND_ABORT;          /* Indicate that event  aborted                */
  473.              break;
  474.                                                         
  475.         case OS_STAT_PEND_TO:                                                
  476.         default:        
  477.             *pmsgs_rdy++ = (void *)0;                   /* NO message returned for timeout             */
  478.             *perr        =  OS_ERR_TIMEOUT;             /* Indicate that events timed out              */
  479.              break;
  480.     }
  481.     OSTCBCur->OSTCBStat          =  OS_STAT_RDY;        /* Set   task  status to ready                 */
  482.     OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;    /* Clear pend  status                          */
  483.     OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;      /* Clear event pointers                        */
  484.     OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  485. #if ((OS_MBOX_EN > 0) ||                 
  486.     ((OS_Q_EN    > 0) && (OS_MAX_QS > 0)))
  487.     OSTCBCur->OSTCBMsg           = (void      *)0;      /* Clear task  message                         */
  488. #endif
  489.     OS_EXIT_CRITICAL();
  490.     return (events_rdy_nbr);
  491. }
  492. #endif
  493. /*$PAGE*/
  494. /*
  495. *********************************************************************************************************
  496. *                                             INITIALIZATION
  497. *
  498. * Description: This function is used to initialize the internals of uC/OS-II and MUST be called prior to
  499. *              creating any uC/OS-II object and, prior to calling OSStart().
  500. *
  501. * Arguments  : none
  502. *
  503. * Returns    : none
  504. *********************************************************************************************************
  505. */
  506. void  OSInit (void)
  507. {
  508.     OSInitHookBegin();                                           /* Call port specific initialization code   */
  509.     OS_InitMisc();                                               /* Initialize miscellaneous variables       */
  510.     OS_InitRdyList();                                            /* Initialize the Ready List                */
  511.     OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */
  512.     OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */
  513. #if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
  514.     OS_FlagInit();                                               /* Initialize the event flag structures     */
  515. #endif
  516. #if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
  517.     OS_MemInit();                                                /* Initialize the memory manager            */
  518. #endif
  519. #if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
  520.     OS_QInit();                                                  /* Initialize the message queue structures  */
  521. #endif
  522.     OS_InitTaskIdle();                                           /* Create the Idle Task                     */
  523. #if OS_TASK_STAT_EN > 0
  524.     OS_InitTaskStat();                                           /* Create the Statistic Task                */
  525. #endif
  526. #if OS_TMR_EN > 0
  527.     OSTmr_Init();                                                /* Initialize the Timer Manager             */
  528. #endif
  529.     OSInitHookEnd();                                             /* Call port specific init. code            */
  530. #if OS_DEBUG_EN > 0
  531.     OSDebugInit();
  532. #endif
  533. }
  534. /*$PAGE*/
  535. /*
  536. *********************************************************************************************************
  537. *                                              ENTER ISR
  538. *
  539. * Description: This function is used to notify uC/OS-II that you are about to service an interrupt
  540. *              service routine (ISR).  This allows uC/OS-II to keep track of interrupt nesting and thus
  541. *              only perform rescheduling at the last nested ISR.
  542. *
  543. * Arguments  : none
  544. *
  545. * Returns    : none
  546. *
  547. * Notes      : 1) This function should be called ith interrupts already disabled
  548. *              2) Your ISR can directly increment OSIntNesting without calling this function because
  549. *                 OSIntNesting has been declared 'global'.
  550. *              3) You MUST still call OSIntExit() even though you increment OSIntNesting directly.
  551. *              4) You MUST invoke OSIntEnter() and OSIntExit() in pair.  In other words, for every call
  552. *                 to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the
  553. *                 end of the ISR.
  554. *              5) You are allowed to nest interrupts up to 255 levels deep.
  555. *              6) I removed the OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() around the increment because
  556. *                 OSIntEnter() is always called with interrupts disabled.
  557. *********************************************************************************************************
  558. */
  559. void  OSIntEnter (void)
  560. {
  561.     if (OSRunning == OS_TRUE) {
  562.         if (OSIntNesting < 255u) {
  563.             OSIntNesting++;                      /* Increment ISR nesting level                        */
  564.         }
  565.     }
  566. }
  567. /*$PAGE*/
  568. /*
  569. *********************************************************************************************************
  570. *                                               EXIT ISR
  571. *
  572. * Description: This function is used to notify uC/OS-II that you have completed serviving an ISR.  When
  573. *              the last nested ISR has completed, uC/OS-II will call the scheduler to determine whether
  574. *              a new, high-priority task, is ready to run.
  575. *
  576. * Arguments  : none
  577. *
  578. * Returns    : none
  579. *
  580. * Notes      : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair.  In other words, for every call
  581. *                 to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the
  582. *                 end of the ISR.
  583. *              2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock())
  584. *********************************************************************************************************
  585. */
  586. void  OSIntExit (void)
  587. {
  588. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  589.     OS_CPU_SR  cpu_sr = 0;
  590. #endif
  591.     if (OSRunning == OS_TRUE) {
  592.         OS_ENTER_CRITICAL();
  593.         if (OSIntNesting > 0) {                            /* Prevent OSIntNesting from wrapping       */
  594.             OSIntNesting--;
  595.         }
  596.         if (OSIntNesting == 0) {                           /* Reschedule only if all ISRs complete ... */
  597.             if (OSLockNesting == 0) {                      /* ... and not locked.                      */
  598.                 OS_SchedNew();
  599.                 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
  600.                 if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy */
  601. #if OS_TASK_PROFILE_EN > 0
  602.                     OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task  */
  603. #endif
  604.                     OSCtxSwCtr++;                          /* Keep track of the number of ctx switches */
  605.                     OSIntCtxSw();                          /* Perform interrupt level ctx switch       */
  606.                 }
  607.             }
  608.         }
  609.         OS_EXIT_CRITICAL();
  610.     }
  611. }
  612. /*$PAGE*/
  613. /*
  614. *********************************************************************************************************
  615. *                                          PREVENT SCHEDULING
  616. *
  617. * Description: This function is used to prevent rescheduling to take place.  This allows your application
  618. *              to prevent context switches until you are ready to permit context switching.
  619. *
  620. * Arguments  : none
  621. *
  622. * Returns    : none
  623. *
  624. * Notes      : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair.  In other words, for every
  625. *                 call to OSSchedLock() you MUST have a call to OSSchedUnlock().
  626. *********************************************************************************************************
  627. */
  628. #if OS_SCHED_LOCK_EN > 0
  629. void  OSSchedLock (void)
  630. {
  631. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  632.     OS_CPU_SR  cpu_sr = 0;
  633. #endif
  634.     if (OSRunning == OS_TRUE) {                  /* Make sure multitasking is running                  */
  635.         OS_ENTER_CRITICAL();
  636.         if (OSIntNesting == 0) {                 /* Can't call from an ISR                             */
  637.             if (OSLockNesting < 255u) {          /* Prevent OSLockNesting from wrapping back to 0      */
  638.                 OSLockNesting++;                 /* Increment lock nesting level                       */
  639.             }
  640.         }
  641.         OS_EXIT_CRITICAL();
  642.     }
  643. }
  644. #endif
  645. /*$PAGE*/
  646. /*
  647. *********************************************************************************************************
  648. *                                          ENABLE SCHEDULING
  649. *
  650. * Description: This function is used to re-allow rescheduling.
  651. *
  652. * Arguments  : none
  653. *
  654. * Returns    : none
  655. *
  656. * Notes      : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair.  In other words, for every
  657. *                 call to OSSchedLock() you MUST have a call to OSSchedUnlock().
  658. *********************************************************************************************************
  659. */
  660. #if OS_SCHED_LOCK_EN > 0
  661. void  OSSchedUnlock (void)
  662. {
  663. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  664.     OS_CPU_SR  cpu_sr = 0;
  665. #endif
  666.     if (OSRunning == OS_TRUE) {                            /* Make sure multitasking is running        */
  667.         OS_ENTER_CRITICAL();
  668.         if (OSLockNesting > 0) {                           /* Do not decrement if already 0            */
  669.             OSLockNesting--;                               /* Decrement lock nesting level             */
  670.             if (OSLockNesting == 0) {                      /* See if scheduler is enabled and ...      */
  671.                 if (OSIntNesting == 0) {                   /* ... not in an ISR                        */
  672.                     OS_EXIT_CRITICAL();
  673.                     OS_Sched();                            /* See if a HPT is ready                    */
  674.                 } else {
  675.                     OS_EXIT_CRITICAL();
  676.                 }
  677.             } else {
  678.                 OS_EXIT_CRITICAL();
  679.             }
  680.         } else {
  681.             OS_EXIT_CRITICAL();
  682.         }
  683.     }
  684. }
  685. #endif
  686. /*$PAGE*/
  687. /*
  688. *********************************************************************************************************
  689. *                                          START MULTITASKING
  690. *
  691. * Description: This function is used to start the multitasking process which lets uC/OS-II manages the
  692. *              task that you have created.  Before you can call OSStart(), you MUST have called OSInit()
  693. *              and you MUST have created at least one task.
  694. *
  695. * Arguments  : none
  696. *
  697. * Returns    : none
  698. *
  699. * Note       : OSStartHighRdy() MUST:
  700. *                 a) Call OSTaskSwHook() then,
  701. *                 b) Set OSRunning to OS_TRUE.
  702. *                 c) Load the context of the task pointed to by OSTCBHighRdy.
  703. *                 d_ Execute the task.
  704. *********************************************************************************************************
  705. */
  706. void  OSStart (void)
  707. {
  708.     if (OSRunning == OS_FALSE) {
  709.         OS_SchedNew();                               /* Find highest priority's task priority number   */
  710.         OSPrioCur     = OSPrioHighRdy;
  711.         OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run    */
  712.         OSTCBCur      = OSTCBHighRdy;
  713.         OSStartHighRdy();                            /* Execute target specific code to start task     */
  714.     }
  715. }
  716. /*$PAGE*/
  717. /*
  718. *********************************************************************************************************
  719. *                                        STATISTICS INITIALIZATION
  720. *
  721. * Description: This function is called by your application to establish CPU usage by first determining
  722. *              how high a 32-bit counter would count to in 1 second if no other tasks were to execute
  723. *              during that time.  CPU usage is then determined by a low priority task which keeps track
  724. *              of this 32-bit counter every second but this time, with other tasks running.  CPU usage is
  725. *              determined by:
  726. *
  727. *                                             OSIdleCtr
  728. *                 CPU Usage (%) = 100 * (1 - ------------)
  729. *                                            OSIdleCtrMax
  730. *
  731. * Arguments  : none
  732. *
  733. * Returns    : none
  734. *********************************************************************************************************
  735. */
  736. #if OS_TASK_STAT_EN > 0
  737. void  OSStatInit (void)
  738. {
  739. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  740.     OS_CPU_SR  cpu_sr = 0;
  741. #endif
  742.     OSTimeDly(2);                                /* Synchronize with clock tick                        */
  743.     OS_ENTER_CRITICAL();
  744.     OSIdleCtr    = 0L;                           /* Clear idle counter                                 */
  745.     OS_EXIT_CRITICAL();
  746.     OSTimeDly(OS_TICKS_PER_SEC / 10);            /* Determine MAX. idle counter value for 1/10 second  */
  747.     OS_ENTER_CRITICAL();
  748.     OSIdleCtrMax = OSIdleCtr;                    /* Store maximum idle counter count in 1/10 second    */
  749.     OSStatRdy    = OS_TRUE;
  750.     OS_EXIT_CRITICAL();
  751. }
  752. #endif
  753. /*$PAGE*/
  754. /*
  755. *********************************************************************************************************
  756. *                                         PROCESS SYSTEM TICK
  757. *
  758. * Description: This function is used to signal to uC/OS-II the occurrence of a 'system tick' (also known
  759. *              as a 'clock tick').  This function should be called by the ticker ISR but, can also be
  760. *              called by a high priority task.
  761. *
  762. * Arguments  : none
  763. *
  764. * Returns    : none
  765. *********************************************************************************************************
  766. */
  767. void  OSTimeTick (void)
  768. {
  769.     OS_TCB    *ptcb;
  770. #if OS_TICK_STEP_EN > 0
  771.     BOOLEAN    step;
  772. #endif
  773. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register     */
  774.     OS_CPU_SR  cpu_sr = 0;
  775. #endif
  776. #if OS_TIME_TICK_HOOK_EN > 0
  777.     OSTimeTickHook();                                      /* Call user definable hook                     */
  778. #endif
  779. #if OS_TIME_GET_SET_EN > 0
  780.     OS_ENTER_CRITICAL();                                   /* Update the 32-bit tick counter               */
  781.     OSTime++;
  782.     OS_EXIT_CRITICAL();
  783. #endif
  784.     if (OSRunning == OS_TRUE) {
  785. #if OS_TICK_STEP_EN > 0
  786.         switch (OSTickStepState) {                         /* Determine whether we need to process a tick  */
  787.             case OS_TICK_STEP_DIS:                         /* Yes, stepping is disabled                    */
  788.                  step = OS_TRUE;
  789.                  break;
  790.             case OS_TICK_STEP_WAIT:                        /* No,  waiting for uC/OS-View to set ...       */
  791.                  step = OS_FALSE;                          /*      .. OSTickStepState to OS_TICK_STEP_ONCE */
  792.                  break;
  793.             case OS_TICK_STEP_ONCE:                        /* Yes, process tick once and wait for next ... */
  794.                  step            = OS_TRUE;                /*      ... step command from uC/OS-View        */
  795.                  OSTickStepState = OS_TICK_STEP_WAIT;
  796.                  break;
  797.             default:                                       /* Invalid case, correct situation              */
  798.                  step            = OS_TRUE;
  799.                  OSTickStepState = OS_TICK_STEP_DIS;
  800.                  break;
  801.         }
  802.         if (step == OS_FALSE) {                            /* Return if waiting for step command           */
  803.             return;
  804.         }
  805. #endif
  806.         ptcb = OSTCBList;                                  /* Point at first TCB in TCB list               */
  807.         while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {     /* Go through all TCBs in TCB list              */
  808.             OS_ENTER_CRITICAL();
  809.             if (ptcb->OSTCBDly != 0) {                     /* No, Delayed or waiting for event with TO     */
  810.                 ptcb->OSTCBDly--;                          /* Decrement nbr of ticks to end of delay       */
  811.                 if (ptcb->OSTCBDly == 0) {                 /* Check for timeout                            */
  812.                                                            
  813.                     if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
  814.                         ptcb->OSTCBStat  &= ~(INT8U)OS_STAT_PEND_ANY;          /* Yes, Clear status flag   */
  815.                         ptcb->OSTCBStatPend = OS_STAT_PEND_TO;                 /* Indicate PEND timeout    */
  816.                     } else {
  817.                         ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
  818.                     }
  819.                     if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  /* Is task suspended?       */
  820.                         OSRdyGrp               |= ptcb->OSTCBBitY;             /* No,  Make ready          */
  821.                         OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  822.                     }
  823.                 }
  824.             }
  825.             ptcb = ptcb->OSTCBNext;                        /* Point at next TCB in TCB list                */
  826.             OS_EXIT_CRITICAL();
  827.         }
  828.     }
  829. }
  830. /*$PAGE*/
  831. /*
  832. *********************************************************************************************************
  833. *                                             GET VERSION
  834. *
  835. * Description: This function is used to return the version number of uC/OS-II.  The returned value
  836. *              corresponds to uC/OS-II's version number multiplied by 100.  In other words, version 2.00
  837. *              would be returned as 200.
  838. *
  839. * Arguments  : none
  840. *
  841. * Returns    : the version number of uC/OS-II multiplied by 100.
  842. *********************************************************************************************************
  843. */
  844. INT16U  OSVersion (void)
  845. {
  846.     return (OS_VERSION);
  847. }
  848. /*$PAGE*/
  849. /*
  850. *********************************************************************************************************
  851. *                                            DUMMY FUNCTION
  852. *
  853. * Description: This function doesn't do anything.  It is called by OSTaskDel().
  854. *
  855. * Arguments  : none
  856. *
  857. * Returns    : none
  858. *********************************************************************************************************
  859. */
  860. #if OS_TASK_DEL_EN > 0
  861. void  OS_Dummy (void)
  862. {
  863. }
  864. #endif
  865. /*$PAGE*/
  866. /*
  867. *********************************************************************************************************
  868. *                             MAKE TASK READY TO RUN BASED ON EVENT OCCURING
  869. *
  870. * Description: This function is called by other uC/OS-II services and is used to ready a task that was
  871. *              waiting for an event to occur.
  872. *
  873. * Arguments  : pevent      is a pointer to the event control block corresponding to the event.
  874. *
  875. *              pmsg        is a pointer to a message.  This pointer is used by message oriented services
  876. *                          such as MAILBOXEs and QUEUEs.  The pointer is not used when called by other
  877. *                          service functions.
  878. *
  879. *              msk         is a mask that is used to clear the status byte of the TCB.  For example,
  880. *                          OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc.
  881. *
  882. *              pend_stat   is used to indicate the readied task's pending status:
  883. *
  884. *                          OS_STAT_PEND_OK      Task ready due to a post (or delete), not a timeout or
  885. *                                               an abort.
  886. *                          OS_STAT_PEND_ABORT   Task ready due to an abort.
  887. *
  888. * Returns    : none
  889. *
  890. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  891. *********************************************************************************************************
  892. */
  893. #if (OS_EVENT_EN)
  894. INT8U  OS_EventTaskRdy (OS_EVENT  *pevent, 
  895.                         void      *pmsg, 
  896.                         INT8U      msk, 
  897.                         INT8U      pend_stat)
  898. {
  899.     OS_TCB  *ptcb;
  900.     INT8U    y;
  901.     INT8U    x;
  902.     INT8U    prio;
  903. #if OS_LOWEST_PRIO > 63
  904.     INT16U  *ptbl;
  905. #endif
  906. #if OS_LOWEST_PRIO <= 63
  907.     y    = OSUnMapTbl[pevent->OSEventGrp];              /* Find HPT waiting for message                */
  908.     x    = OSUnMapTbl[pevent->OSEventTbl[y]];
  909.     prio = (INT8U)((y << 3) + x);                       /* Find priority of task getting the msg       */
  910. #else
  911.     if ((pevent->OSEventGrp & 0xFF) != 0) {             /* Find HPT waiting for message                */
  912.         y = OSUnMapTbl[ pevent->OSEventGrp & 0xFF];
  913.     } else {
  914.         y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
  915.     }
  916.     ptbl = &pevent->OSEventTbl[y];
  917.     if ((*ptbl & 0xFF) != 0) {
  918.         x = OSUnMapTbl[*ptbl & 0xFF];
  919.     } else {
  920.         x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
  921.     }
  922.     prio = (INT8U)((y << 4) + x);                       /* Find priority of task getting the msg       */
  923. #endif
  924.     ptcb                  =  OSTCBPrioTbl[prio];        /* Point to this task's OS_TCB                 */
  925.     ptcb->OSTCBDly        =  0;                         /* Prevent OSTimeTick() from readying task     */
  926. #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
  927.     ptcb->OSTCBMsg        =  pmsg;                      /* Send message directly to waiting task       */
  928. #else
  929.     pmsg                  =  pmsg;                      /* Prevent compiler warning if not used        */
  930. #endif
  931.     ptcb->OSTCBStat      &= ~msk;                       /* Clear bit associated with event type        */
  932.     ptcb->OSTCBStatPend   =  pend_stat;                 /* Set pend status of post or abort            */
  933.                                                         /* See if task is ready (could be susp'd)      */
  934.     if ((ptcb->OSTCBStat &   OS_STAT_SUSPEND) == OS_STAT_RDY) {
  935.         OSRdyGrp         |=  ptcb->OSTCBBitY;           /* Put task in the ready to run list           */
  936.         OSRdyTbl[y]      |=  ptcb->OSTCBBitX;
  937.     }
  938.     OS_EventTaskRemove(ptcb, pevent);                   /* Remove this task from event   wait list     */
  939. #if (OS_EVENT_MULTI_EN > 0)
  940.     if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {   /* Remove this task from events' wait lists    */
  941.         OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
  942.         ptcb->OSTCBEventPtr       = (OS_EVENT  *)pevent;/* Return event as first multi-pend event ready*/
  943.     }
  944. #endif
  945.     return (prio);
  946. }
  947. #endif
  948. /*$PAGE*/
  949. /*
  950. *********************************************************************************************************
  951. *                                   MAKE TASK WAIT FOR EVENT TO OCCUR
  952. *
  953. * Description: This function is called by other uC/OS-II services to suspend a task because an event has
  954. *              not occurred.
  955. *
  956. * Arguments  : pevent   is a pointer to the event control block for which the task will be waiting for.
  957. *
  958. * Returns    : none
  959. *
  960. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  961. *********************************************************************************************************
  962. */
  963. #if (OS_EVENT_EN)
  964. void  OS_EventTaskWait (OS_EVENT *pevent)
  965. {
  966.     INT8U  y;
  967.     OSTCBCur->OSTCBEventPtr               = pevent;                 /* Store ptr to ECB in TCB         */
  968.     pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;    /* Put task in waiting list        */
  969.     pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;
  970.     y             =  OSTCBCur->OSTCBY;            /* Task no longer ready                              */
  971.     OSRdyTbl[y]  &= ~OSTCBCur->OSTCBBitX;
  972.     if (OSRdyTbl[y] == 0) {
  973.         OSRdyGrp &= ~OSTCBCur->OSTCBBitY;         /* Clear event grp bit if this was only task pending */
  974.     }
  975. }
  976. #endif
  977. /*$PAGE*/
  978. /*
  979. *********************************************************************************************************
  980. *                          MAKE TASK WAIT FOR ANY OF MULTIPLE EVENTS TO OCCUR
  981. *
  982. * Description: This function is called by other uC/OS-II services to suspend a task because any one of
  983. *              multiple events has not occurred.
  984. *
  985. * Arguments  : pevents_wait     is a pointer to an array of event control blocks, NULL-terminated, for 
  986. *                               which the task will be waiting for.
  987. *
  988. * Returns    : none.
  989. *
  990. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  991. *********************************************************************************************************
  992. */
  993. #if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0))
  994. void  OS_EventTaskWaitMulti (OS_EVENT **pevents_wait)
  995. {
  996.     OS_EVENT **pevents;
  997.     OS_EVENT  *pevent;
  998.     INT8U      y;
  999.     OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;
  1000.     OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)pevents_wait;       /* Store ptr to ECBs in TCB        */
  1001.     pevents =  pevents_wait;
  1002.     pevent  = *pevents;
  1003.     while (pevent != (OS_EVENT *)0) {                               /* Put task in waiting lists       */
  1004.         pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
  1005.         pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;
  1006.         pevents++;
  1007.         pevent = *pevents;
  1008.     }
  1009.     y             =  OSTCBCur->OSTCBY;            /* Task no longer ready                              */
  1010.     OSRdyTbl[y]  &= ~OSTCBCur->OSTCBBitX;
  1011.     if (OSRdyTbl[y] == 0) {
  1012.         OSRdyGrp &= ~OSTCBCur->OSTCBBitY;         /* Clear event grp bit if this was only task pending */
  1013.     }
  1014. }
  1015. #endif
  1016. /*$PAGE*/
  1017. /*
  1018. *********************************************************************************************************
  1019. *                                   REMOVE TASK FROM EVENT WAIT LIST
  1020. *
  1021. * Description: Remove a task from an event's wait list.
  1022. *
  1023. * Arguments  : ptcb     is a pointer to the task to remove.
  1024. *
  1025. *              pevent   is a pointer to the event control block.
  1026. *
  1027. * Returns    : none
  1028. *
  1029. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  1030. *********************************************************************************************************
  1031. */
  1032. #if (OS_EVENT_EN)
  1033. void  OS_EventTaskRemove (OS_TCB   *ptcb,
  1034.                           OS_EVENT *pevent)
  1035. {
  1036.     INT8U  y;
  1037.     y                       =  ptcb->OSTCBY;
  1038.     pevent->OSEventTbl[y]  &= ~ptcb->OSTCBBitX;         /* Remove task from wait list                  */
  1039.     if (pevent->OSEventTbl[y] == 0) {
  1040.         pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
  1041.     }
  1042. }
  1043. #endif
  1044. /*$PAGE*/
  1045. /*
  1046. *********************************************************************************************************
  1047. *                             REMOVE TASK FROM MULTIPLE EVENTS WAIT LISTS
  1048. *
  1049. * Description: Remove a task from multiple events' wait lists.
  1050. *
  1051. * Arguments  : ptcb             is a pointer to the task to remove.
  1052. *
  1053. *              pevents_multi    is a pointer to the array of event control blocks, NULL-terminated.
  1054. *
  1055. * Returns    : none
  1056. *
  1057. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  1058. *********************************************************************************************************
  1059. */
  1060. #if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0))
  1061. void  OS_EventTaskRemoveMulti (OS_TCB    *ptcb,
  1062.                                OS_EVENT **pevents_multi)
  1063. {
  1064.     OS_EVENT **pevents;
  1065.     OS_EVENT  *pevent;
  1066.     INT8U      y;
  1067. #if (OS_LOWEST_PRIO <= 63)
  1068.     INT8U      bity;
  1069.     INT8U      bitx;
  1070. #else
  1071.     INT16U     bity;
  1072.     INT16U     bitx;
  1073. #endif
  1074.     y       =  ptcb->OSTCBY;
  1075.     bity    =  ptcb->OSTCBBitY;
  1076.     bitx    =  ptcb->OSTCBBitX;
  1077.     pevents =  pevents_multi;
  1078.     pevent  = *pevents;
  1079.     while (pevent != (OS_EVENT *)0) {                   /* Remove task from all events' wait lists     */
  1080.         pevent->OSEventTbl[y]  &= ~bitx;
  1081.         if (pevent->OSEventTbl[y] == 0) {
  1082.             pevent->OSEventGrp &= ~bity;
  1083.         }
  1084.         pevents++;
  1085.         pevent = *pevents;
  1086.     }
  1087. }
  1088. #endif
  1089. /*$PAGE*/
  1090. /*
  1091. *********************************************************************************************************
  1092. *                                 INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
  1093. *
  1094. * Description: This function is called by other uC/OS-II services to initialize the event wait list.
  1095. *
  1096. * Arguments  : pevent    is a pointer to the event control block allocated to the event.
  1097. *
  1098. * Returns    : none
  1099. *
  1100. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  1101. *********************************************************************************************************
  1102. */
  1103. #if (OS_EVENT_EN)
  1104. void  OS_EventWaitListInit (OS_EVENT *pevent)
  1105. {
  1106. #if OS_LOWEST_PRIO <= 63
  1107.     INT8U  *ptbl;
  1108. #else
  1109.     INT16U *ptbl;
  1110. #endif
  1111.     INT8U   i;
  1112.     pevent->OSEventGrp = 0;                      /* No task waiting on event                           */
  1113.     ptbl               = &pevent->OSEventTbl[0];
  1114.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  1115.         *ptbl++ = 0;
  1116.     }
  1117. }
  1118. #endif
  1119. /*$PAGE*/
  1120. /*
  1121. *********************************************************************************************************
  1122. *                                             INITIALIZATION
  1123. *                           INITIALIZE THE FREE LIST OF EVENT CONTROL BLOCKS
  1124. *
  1125. * Description: This function is called by OSInit() to initialize the free list of event control blocks.
  1126. *
  1127. * Arguments  : none
  1128. *
  1129. * Returns    : none
  1130. *********************************************************************************************************
  1131. */
  1132. static  void  OS_InitEventList (void)
  1133. {
  1134. #if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0)
  1135. #if (OS_MAX_EVENTS > 1)
  1136.     INT16U     i;
  1137.     OS_EVENT  *pevent1;
  1138.     OS_EVENT  *pevent2;
  1139.     OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table                   */
  1140.     pevent1 = &OSEventTbl[0];
  1141.     pevent2 = &OSEventTbl[1];
  1142.     for (i = 0; i < (OS_MAX_EVENTS - 1); i++) {             /* Init. list of free EVENT control blocks */
  1143.         pevent1->OSEventType    = OS_EVENT_TYPE_UNUSED;
  1144.         pevent1->OSEventPtr     = pevent2;
  1145. #if OS_EVENT_NAME_EN > 0
  1146.         pevent1->OSEventName    = "?";                      /* Unknown name                            */
  1147. #endif
  1148.         pevent1++;
  1149.         pevent2++;
  1150.     }
  1151.     pevent1->OSEventType            = OS_EVENT_TYPE_UNUSED;
  1152.     pevent1->OSEventPtr             = (OS_EVENT *)0;
  1153. #if OS_EVENT_NAME_EN > 0
  1154.     pevent1->OSEventName            = "?";                  /* Unknown name                            */
  1155. #endif
  1156.     OSEventFreeList                 = &OSEventTbl[0];
  1157. #else
  1158.     OSEventFreeList                 = &OSEventTbl[0];       /* Only have ONE event control block       */
  1159.     OSEventFreeList->OSEventType    = OS_EVENT_TYPE_UNUSED;
  1160.     OSEventFreeList->OSEventPtr     = (OS_EVENT *)0;
  1161. #if OS_EVENT_NAME_EN > 0
  1162.     OSEventFreeList->OSEventName    = "?";                  /* Unknown name                            */
  1163. #endif
  1164. #endif
  1165. #endif
  1166. }
  1167. /*$PAGE*/
  1168. /*
  1169. *********************************************************************************************************
  1170. *                                             INITIALIZATION
  1171. *                                    INITIALIZE MISCELLANEOUS VARIABLES
  1172. *
  1173. * Description: This function is called by OSInit() to initialize miscellaneous variables.
  1174. *
  1175. * Arguments  : none
  1176. *
  1177. * Returns    : none
  1178. *********************************************************************************************************
  1179. */
  1180. static  void  OS_InitMisc (void)
  1181. {
  1182. #if OS_TIME_GET_SET_EN > 0
  1183.     OSTime        = 0L;                                    /* Clear the 32-bit system clock            */
  1184. #endif
  1185.     OSIntNesting  = 0;                                     /* Clear the interrupt nesting counter      */
  1186.     OSLockNesting = 0;                                     /* Clear the scheduling lock counter        */
  1187.     OSTaskCtr     = 0;                                     /* Clear the number of tasks                */
  1188.     OSRunning     = OS_FALSE;                              /* Indicate that multitasking not started   */
  1189.     OSCtxSwCtr    = 0;                                     /* Clear the context switch counter         */
  1190.     OSIdleCtr     = 0L;                                    /* Clear the 32-bit idle counter            */
  1191. #if OS_TASK_STAT_EN > 0
  1192.     OSIdleCtrRun  = 0L;
  1193.     OSIdleCtrMax  = 0L;
  1194.     OSStatRdy     = OS_FALSE;                              /* Statistic task is not ready              */
  1195. #endif
  1196. }
  1197. /*$PAGE*/
  1198. /*
  1199. *********************************************************************************************************
  1200. *                                             INITIALIZATION
  1201. *                                       INITIALIZE THE READY LIST
  1202. *
  1203. * Description: This function is called by OSInit() to initialize the Ready List.
  1204. *
  1205. * Arguments  : none
  1206. *
  1207. * Returns    : none
  1208. *********************************************************************************************************
  1209. */
  1210. static  void  OS_InitRdyList (void)
  1211. {
  1212.     INT8U    i;
  1213. #if OS_LOWEST_PRIO <= 63
  1214.     INT8U   *prdytbl;
  1215. #else
  1216.     INT16U  *prdytbl;
  1217. #endif
  1218.     OSRdyGrp      = 0;                                     /* Clear the ready list                     */
  1219.     prdytbl       = &OSRdyTbl[0];
  1220.     for (i = 0; i < OS_RDY_TBL_SIZE; i++) {
  1221.         *prdytbl++ = 0;
  1222.     }
  1223.     OSPrioCur     = 0;
  1224.     OSPrioHighRdy = 0;
  1225.     OSTCBHighRdy  = (OS_TCB *)0;
  1226.     OSTCBCur      = (OS_TCB *)0;
  1227. }
  1228. /*$PAGE*/
  1229. /*
  1230. *********************************************************************************************************
  1231. *                                             INITIALIZATION
  1232. *                                         CREATING THE IDLE TASK
  1233. *
  1234. * Description: This function creates the Idle Task.
  1235. *
  1236. * Arguments  : none
  1237. *
  1238. * Returns    : none
  1239. *********************************************************************************************************
  1240. */
  1241. static  void  OS_InitTaskIdle (void)
  1242. {
  1243. #if OS_TASK_NAME_EN > 0
  1244.     INT8U  err;
  1245. #endif
  1246. #if OS_TASK_CREATE_EXT_EN > 0
  1247.     #if OS_STK_GROWTH == 1
  1248.     (void)OSTaskCreateExt(OS_TaskIdle,
  1249.                           (void *)0,                                 /* No arguments passed to OS_TaskIdle() */
  1250.                           &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /* Set Top-Of-Stack                     */
  1251.                           OS_TASK_IDLE_PRIO,                         /* Lowest priority level                */
  1252.                           OS_TASK_IDLE_ID,
  1253.                           &OSTaskIdleStk[0],                         /* Set Bottom-Of-Stack                  */
  1254.                           OS_TASK_IDLE_STK_SIZE,
  1255.                           (void *)0,                                 /* No TCB extension                     */
  1256.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack  */
  1257.     #else
  1258.     (void)OSTaskCreateExt(OS_TaskIdle,
  1259.                           (void *)0,                                 /* No arguments passed to OS_TaskIdle() */
  1260.                           &OSTaskIdleStk[0],                         /* Set Top-Of-Stack                     */
  1261.                           OS_TASK_IDLE_PRIO,                         /* Lowest priority level                */
  1262.                           OS_TASK_IDLE_ID,
  1263.                           &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /* Set Bottom-Of-Stack                  */
  1264.                           OS_TASK_IDLE_STK_SIZE,
  1265.                           (void *)0,                                 /* No TCB extension                     */
  1266.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack  */
  1267.     #endif
  1268. #else
  1269.     #if OS_STK_GROWTH == 1
  1270.     (void)OSTaskCreate(OS_TaskIdle,
  1271.                        (void *)0,
  1272.                        &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],
  1273.                        OS_TASK_IDLE_PRIO);
  1274.     #else
  1275.     (void)OSTaskCreate(OS_TaskIdle,
  1276.                        (void *)0,
  1277.                        &OSTaskIdleStk[0],
  1278.                        OS_TASK_IDLE_PRIO);
  1279.     #endif
  1280. #endif
  1281. #if OS_TASK_NAME_EN > 0
  1282.     OSTaskNameSet(OS_TASK_IDLE_PRIO, (INT8U *)"uC/OS-II Idle", &err);
  1283. #endif
  1284. }
  1285. /*$PAGE*/
  1286. /*
  1287. *********************************************************************************************************
  1288. *                                             INITIALIZATION
  1289. *                                      CREATING THE STATISTIC TASK
  1290. *
  1291. * Description: This function creates the Statistic Task.
  1292. *
  1293. * Arguments  : none
  1294. *
  1295. * Returns    : none
  1296. *********************************************************************************************************
  1297. */
  1298. #if OS_TASK_STAT_EN > 0
  1299. static  void  OS_InitTaskStat (void)
  1300. {
  1301. #if OS_TASK_NAME_EN > 0
  1302.     INT8U  err;
  1303. #endif
  1304. #if OS_TASK_CREATE_EXT_EN > 0
  1305.     #if OS_STK_GROWTH == 1
  1306.     (void)OSTaskCreateExt(OS_TaskStat,
  1307.                           (void *)0,                                   /* No args passed to OS_TaskStat()*/
  1308.                           &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Top-Of-Stack               */
  1309.                           OS_TASK_STAT_PRIO,                           /* One higher than the idle task  */
  1310.                           OS_TASK_STAT_ID,
  1311.                           &OSTaskStatStk[0],                           /* Set Bottom-Of-Stack            */
  1312.                           OS_TASK_STAT_STK_SIZE,
  1313.                           (void *)0,                                   /* No TCB extension               */
  1314.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
  1315.     #else
  1316.     (void)OSTaskCreateExt(OS_TaskStat,
  1317.                           (void *)0,                                   /* No args passed to OS_TaskStat()*/
  1318.                           &OSTaskStatStk[0],                           /* Set Top-Of-Stack               */
  1319.                           OS_TASK_STAT_PRIO,                           /* One higher than the idle task  */
  1320.                           OS_TASK_STAT_ID,
  1321.                           &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Bottom-Of-Stack            */
  1322.                           OS_TASK_STAT_STK_SIZE,
  1323.                           (void *)0,                                   /* No TCB extension               */
  1324.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
  1325.     #endif
  1326. #else
  1327.     #if OS_STK_GROWTH == 1
  1328.     (void)OSTaskCreate(OS_TaskStat,
  1329.                        (void *)0,                                      /* No args passed to OS_TaskStat()*/
  1330.                        &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],      /* Set Top-Of-Stack               */
  1331.                        OS_TASK_STAT_PRIO);                             /* One higher than the idle task  */
  1332.     #else
  1333.     (void)OSTaskCreate(OS_TaskStat,
  1334.                        (void *)0,                                      /* No args passed to OS_TaskStat()*/
  1335.                        &OSTaskStatStk[0],                              /* Set Top-Of-Stack               */
  1336.                        OS_TASK_STAT_PRIO);                             /* One higher than the idle task  */
  1337.     #endif
  1338. #endif
  1339. #if OS_TASK_NAME_EN > 0
  1340.     OSTaskNameSet(OS_TASK_STAT_PRIO, (INT8U *)"uC/OS-II Stat", &err);
  1341. #endif
  1342. }
  1343. #endif
  1344. /*$PAGE*/
  1345. /*
  1346. *********************************************************************************************************
  1347. *                                             INITIALIZATION
  1348. *                            INITIALIZE THE FREE LIST OF TASK CONTROL BLOCKS
  1349. *
  1350. * Description: This function is called by OSInit() to initialize the free list of OS_TCBs.
  1351. *
  1352. * Arguments  : none
  1353. *
  1354. * Returns    : none
  1355. *********************************************************************************************************
  1356. */
  1357. static  void  OS_InitTCBList (void)
  1358. {
  1359.     INT8U    i;
  1360.     OS_TCB  *ptcb1;
  1361.     OS_TCB  *ptcb2;
  1362.     OS_MemClr((INT8U *)&OSTCBTbl[0],     sizeof(OSTCBTbl));      /* Clear all the TCBs                 */
  1363.     OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl));  /* Clear the priority table           */
  1364.     ptcb1 = &OSTCBTbl[0];
  1365.     ptcb2 = &OSTCBTbl[1];
  1366.     for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) {  /* Init. list of free TCBs            */
  1367.         ptcb1->OSTCBNext = ptcb2;
  1368. #if OS_TASK_NAME_EN > 0
  1369.         ptcb1->OSTCBTaskName = "?";                              /* Unknown name                       */
  1370. #endif
  1371.         ptcb1++;
  1372.         ptcb2++;
  1373.     }
  1374.     ptcb1->OSTCBNext = (OS_TCB *)0;                              /* Last OS_TCB                        */
  1375. #if OS_TASK_NAME_EN > 0
  1376.     ptcb1->OSTCBTaskName    = "?";                               /* Unknown name                       */
  1377. #endif
  1378.     OSTCBList               = (OS_TCB *)0;                       /* TCB lists initializations          */
  1379.     OSTCBFreeList           = &OSTCBTbl[0];
  1380. }
  1381. /*$PAGE*/
  1382. /*
  1383. *********************************************************************************************************
  1384. *                                        CLEAR A SECTION OF MEMORY
  1385. *
  1386. * Description: This function is called by other uC/OS-II services to clear a contiguous block of RAM.
  1387. *
  1388. * Arguments  : pdest    is the start of the RAM to clear (i.e. write 0x00 to)
  1389. *
  1390. *              size     is the number of bytes to clear.
  1391. *
  1392. * Returns    : none
  1393. *
  1394. * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
  1395. *              2) Note that we can only clear up to 64K bytes of RAM.  This is not an issue because none
  1396. *                 of the uses of this function gets close to this limit.
  1397. *              3) The clear is done one byte at a time since this will work on any processor irrespective
  1398. *                 of the alignment of the destination.
  1399. *********************************************************************************************************
  1400. */
  1401. void  OS_MemClr (INT8U  *pdest, 
  1402.                  INT16U  size)
  1403. {
  1404.     while (size > 0) {
  1405.         *pdest++ = (INT8U)0;
  1406.         size--;
  1407.     }
  1408. }
  1409. /*$PAGE*/
  1410. /*
  1411. *********************************************************************************************************
  1412. *                                        COPY A BLOCK OF MEMORY
  1413. *
  1414. * Description: This function is called by other uC/OS-II services to copy a block of memory from one
  1415. *              location to another.
  1416. *
  1417. * Arguments  : pdest    is a pointer to the 'destination' memory block
  1418. *
  1419. *              psrc     is a pointer to the 'source'      memory block
  1420. *
  1421. *              size     is the number of bytes to copy.
  1422. *
  1423. * Returns    : none
  1424. *
  1425. * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.  There is
  1426. *                 no provision to handle overlapping memory copy.  However, that's not a problem since this
  1427. *                 is not a situation that will happen.
  1428. *              2) Note that we can only copy up to 64K bytes of RAM
  1429. *              3) The copy is done one byte at a time since this will work on any processor irrespective
  1430. *                 of the alignment of the source and destination.
  1431. *********************************************************************************************************
  1432. */
  1433. void  OS_MemCopy (INT8U  *pdest, 
  1434.                   INT8U  *psrc, 
  1435.                   INT16U  size)
  1436. {
  1437.     while (size > 0) {
  1438.         *pdest++ = *psrc++;
  1439.         size--;
  1440.     }
  1441. }
  1442. /*$PAGE*/
  1443. /*
  1444. *********************************************************************************************************
  1445. *                                              SCHEDULER
  1446. *
  1447. * Description: This function is called by other uC/OS-II services to determine whether a new, high
  1448. *              priority task has been made ready to run.  This function is invoked by TASK level code
  1449. *              and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling).
  1450. *
  1451. * Arguments  : none
  1452. *
  1453. * Returns    : none
  1454. *
  1455. * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
  1456. *              2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock())
  1457. *********************************************************************************************************
  1458. */
  1459. void  OS_Sched (void)
  1460. {
  1461. #if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
  1462.     OS_CPU_SR  cpu_sr = 0;
  1463. #endif
  1464.     OS_ENTER_CRITICAL();
  1465.     if (OSIntNesting == 0) {                           /* Schedule only if all ISRs done and ...       */
  1466.         if (OSLockNesting == 0) {                      /* ... scheduler is not locked                  */
  1467.             OS_SchedNew();
  1468.             OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
  1469.             if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
  1470. #if OS_TASK_PROFILE_EN > 0
  1471.                 OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
  1472. #endif
  1473.                 OSCtxSwCtr++;                          /* Increment context switch counter             */
  1474.                 OS_TASK_SW();                          /* Perform a context switch                     */
  1475.             }
  1476.         }
  1477.     }
  1478.     OS_EXIT_CRITICAL();
  1479. }
  1480. /*
  1481. *********************************************************************************************************
  1482. *                              FIND HIGHEST PRIORITY TASK READY TO RUN
  1483. *
  1484. * Description: This function is called by other uC/OS-II services to determine the highest priority task
  1485. *              that is ready to run.  The global variable 'OSPrioHighRdy' is changed accordingly.
  1486. *
  1487. * Arguments  : none
  1488. *
  1489. * Returns    : none
  1490. *
  1491. * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
  1492. *              2) Interrupts are assumed to be disabled when this function is called.
  1493. *********************************************************************************************************
  1494. */
  1495. static  void  OS_SchedNew (void)
  1496. {
  1497. #if OS_LOWEST_PRIO <= 63                         /* See if we support up to 64 tasks                   */
  1498.     INT8U   y;
  1499.     y             = OSUnMapTbl[OSRdyGrp];
  1500.     OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
  1501. #else                                            /* We support up to 256 tasks                         */
  1502.     INT8U   y;
  1503.     INT16U *ptbl;
  1504.     if ((OSRdyGrp & 0xFF) != 0) {
  1505.         y = OSUnMapTbl[OSRdyGrp & 0xFF];
  1506.     } else {
  1507.         y = OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8;
  1508.     }
  1509.     ptbl = &OSRdyTbl[y];
  1510.     if ((*ptbl & 0xFF) != 0) {
  1511.         OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl & 0xFF)]);
  1512.     } else {
  1513.         OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8);
  1514.     }
  1515. #endif
  1516. }
  1517. /*$PAGE*/
  1518. /*
  1519. *********************************************************************************************************
  1520. *                                DETERMINE THE LENGTH OF AN ASCII STRING
  1521. *
  1522. * Description: This function is called by other uC/OS-II services to determine the size of an ASCII string
  1523. *              (excluding the NUL character).
  1524. *
  1525. * Arguments  : psrc     is a pointer to the string for which we need to know the size.
  1526. *
  1527. * Returns    : The size of the string (excluding the NUL terminating character)
  1528. *
  1529. * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
  1530. *              2) The string to check must be less than 255 characters long.
  1531. *********************************************************************************************************
  1532. */
  1533. #if (OS_EVENT_NAME_EN > 0) || (OS_FLAG_NAME_EN > 0) || (OS_MEM_NAME_EN > 0) || (OS_TASK_NAME_EN > 0) || (OS_TMR_CFG_NAME_EN > 0)
  1534. INT8U  OS_StrLen (INT8U *psrc)
  1535. {
  1536.     INT8U  len;
  1537.     len = 0;
  1538.     while (*psrc != OS_ASCII_NUL) {
  1539.         psrc++;
  1540.         len++;
  1541.     }
  1542.     return (len);
  1543. }
  1544. #endif
  1545. /*$PAGE*/
  1546. /*
  1547. *********************************************************************************************************
  1548. *                                              IDLE TASK
  1549. *
  1550. * Description: This task is internal to uC/OS-II and executes whenever no other higher priority tasks
  1551. *              executes because they are ALL waiting for event(s) to occur.
  1552. *
  1553. * Arguments  : none
  1554. *
  1555. * Returns    : none
  1556. *
  1557. * Note(s)    : 1) OSTaskIdleHook() is called after the critical section to ensure that interrupts will be
  1558. *                 enabled for at least a few instructions.  On some processors (ex. Philips XA), enabling
  1559. *                 and then disabling interrupts didn't allow the processor enough time to have interrupts
  1560. *                 enabled before they were disabled again.  uC/OS-II would thus never recognize
  1561. *                 interrupts.
  1562. *              2) This hook has been added to allow you to do such things as STOP the CPU to conserve
  1563. *                 power.
  1564. *********************************************************************************************************
  1565. */
  1566. void  OS_TaskIdle (void *p_arg)
  1567. {
  1568. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  1569.     OS_CPU_SR  cpu_sr = 0;
  1570. #endif
  1571.     (void)p_arg;                                 /* Prevent compiler warning for not using 'p_arg'     */
  1572.     for (;;) {
  1573.         OS_ENTER_CRITICAL();
  1574.         OSIdleCtr++;
  1575.         OS_EXIT_CRITICAL();
  1576.         OSTaskIdleHook();                        /* Call user definable HOOK                           */
  1577.     }
  1578. }
  1579. /*$PAGE*/
  1580. /*
  1581. *********************************************************************************************************
  1582. *                                            STATISTICS TASK
  1583. *
  1584. * Description: This task is internal to uC/OS-II and is used to compute some statistics about the
  1585. *              multitasking environment.  Specifically, OS_TaskStat() computes the CPU usage.
  1586. *              CPU usage is determined by:
  1587. *
  1588. *                                          OSIdleCtr
  1589. *                 OSCPUUsage = 100 * (1 - ------------)     (units are in %)
  1590. *                                         OSIdleCtrMax
  1591. *
  1592. * Arguments  : parg     this pointer is not used at this time.
  1593. *
  1594. * Returns    : none
  1595. *
  1596. * Notes      : 1) This task runs at a priority level higher than the idle task.  In fact, it runs at the
  1597. *                 next higher priority, OS_TASK_IDLE_PRIO-1.
  1598. *              2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0.
  1599. *              3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the
  1600. *                 maximum value for the idle counter.
  1601. *********************************************************************************************************
  1602. */
  1603. #if OS_TASK_STAT_EN > 0
  1604. void  OS_TaskStat (void *p_arg)
  1605. {
  1606. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  1607.     OS_CPU_SR  cpu_sr = 0;
  1608. #endif
  1609.     (void)p_arg;                                 /* Prevent compiler warning for not using 'p_arg'     */
  1610.     while (OSStatRdy == OS_FALSE) {
  1611.         OSTimeDly(2 * OS_TICKS_PER_SEC / 10);    /* Wait until statistic task is ready                 */
  1612.     }
  1613.     OSIdleCtrMax /= 100L;
  1614.     if (OSIdleCtrMax == 0L) {
  1615.         OSCPUUsage = 0;
  1616.         (void)OSTaskSuspend(OS_PRIO_SELF);
  1617.     }
  1618.     for (;;) {
  1619.         OS_ENTER_CRITICAL();
  1620.         OSIdleCtrRun = OSIdleCtr;                /* Obtain the of the idle counter for the past second */
  1621.         OSIdleCtr    = 0L;                       /* Reset the idle counter for the next second         */
  1622.         OS_EXIT_CRITICAL();
  1623.         OSCPUUsage   = (INT8U)(100L - OSIdleCtrRun / OSIdleCtrMax);
  1624.         OSTaskStatHook();                        /* Invoke user definable hook                         */
  1625. #if (OS_TASK_STAT_STK_CHK_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
  1626.         OS_TaskStatStkChk();                     /* Check the stacks for each task                     */
  1627. #endif
  1628.         OSTimeDly(OS_TICKS_PER_SEC / 10);        /* Accumulate OSIdleCtr for the next 1/10 second      */
  1629.     }
  1630. }
  1631. #endif
  1632. /*$PAGE*/
  1633. /*
  1634. *********************************************************************************************************
  1635. *                                      CHECK ALL TASK STACKS
  1636. *
  1637. * Description: This function is called by OS_TaskStat() to check the stacks of each active task.
  1638. *
  1639. * Arguments  : none
  1640. *
  1641. * Returns    : none
  1642. *********************************************************************************************************
  1643. */
  1644. #if (OS_TASK_STAT_STK_CHK_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
  1645. void  OS_TaskStatStkChk (void)
  1646. {
  1647.     OS_TCB      *ptcb;
  1648.     OS_STK_DATA  stk_data;
  1649.     INT8U        err;
  1650.     INT8U        prio;
  1651.     for (prio = 0; prio <= OS_TASK_IDLE_PRIO; prio++) {
  1652.         err = OSTaskStkChk(prio, &stk_data);
  1653.         if (err == OS_ERR_NONE) {
  1654.             ptcb = OSTCBPrioTbl[prio];
  1655.             if (ptcb != (OS_TCB *)0) {                               /* Make sure task 'ptcb' is ...   */
  1656.                 if (ptcb != OS_TCB_RESERVED) {                       /* ... still valid.               */
  1657. #if OS_TASK_PROFILE_EN > 0
  1658.                     #if OS_STK_GROWTH == 1
  1659.                     ptcb->OSTCBStkBase = ptcb->OSTCBStkBottom + ptcb->OSTCBStkSize;
  1660.                     #else
  1661.                     ptcb->OSTCBStkBase = ptcb->OSTCBStkBottom - ptcb->OSTCBStkSize;
  1662.                     #endif
  1663.                     ptcb->OSTCBStkUsed = stk_data.OSUsed;            /* Store the number of bytes used */
  1664. #endif
  1665.                 }
  1666.             }
  1667.         }
  1668.     }
  1669. }
  1670. #endif
  1671. /*$PAGE*/
  1672. /*
  1673. *********************************************************************************************************
  1674. *                                            INITIALIZE TCB
  1675. *
  1676. * Description: This function is internal to uC/OS-II and is used to initialize a Task Control Block when
  1677. *              a task is created (see OSTaskCreate() and OSTaskCreateExt()).
  1678. *
  1679. * Arguments  : prio          is the priority of the task being created
  1680. *
  1681. *              ptos          is a pointer to the task's top-of-stack assuming that the CPU registers
  1682. *                            have been placed on the stack.  Note that the top-of-stack corresponds to a
  1683. *                            'high' memory location is OS_STK_GROWTH is set to 1 and a 'low' memory
  1684. *                            location if OS_STK_GROWTH is set to 0.  Note that stack growth is CPU
  1685. *                            specific.
  1686. *
  1687. *              pbos          is a pointer to the bottom of stack.  A NULL pointer is passed if called by
  1688. *                            'OSTaskCreate()'.
  1689. *
  1690. *              id            is the task's ID (0..65535)
  1691. *
  1692. *              stk_size      is the size of the stack (in 'stack units').  If the stack units are INT8Us
  1693. *                            then, 'stk_size' contains the number of bytes for the stack.  If the stack
  1694. *                            units are INT32Us then, the stack contains '4 * stk_size' bytes.  The stack
  1695. *                            units are established by the #define constant OS_STK which is CPU
  1696. *                            specific.  'stk_size' is 0 if called by 'OSTaskCreate()'.
  1697. *
  1698. *              pext          is a pointer to a user supplied memory area that is used to extend the task
  1699. *                            control block.  This allows you to store the contents of floating-point
  1700. *                            registers, MMU registers or anything else you could find useful during a
  1701. *                            context switch.  You can even assign a name to each task and store this name
  1702. *                            in this TCB extension.  A NULL pointer is passed if called by OSTaskCreate().
  1703. *
  1704. *              opt           options as passed to 'OSTaskCreateExt()' or,
  1705. *                            0 if called from 'OSTaskCreate()'.
  1706. *
  1707. * Returns    : OS_ERR_NONE         if the call was successful
  1708. *              OS_ERR_TASK_NO_MORE_TCB  if there are no more free TCBs to be allocated and thus, the task cannot
  1709. *                                  be created.
  1710. *
  1711. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  1712. *********************************************************************************************************
  1713. */
  1714. INT8U  OS_TCBInit (INT8U    prio, 
  1715.                    OS_STK  *ptos, 
  1716.                    OS_STK  *pbos, 
  1717.                    INT16U   id, 
  1718.                    INT32U   stk_size, 
  1719.                    void    *pext, 
  1720.                    INT16U   opt)
  1721. {
  1722.     OS_TCB    *ptcb;
  1723. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  1724.     OS_CPU_SR  cpu_sr = 0;
  1725. #endif
  1726. #if OS_TASK_REG_TBL_SIZE > 0
  1727.     INT8U      i;
  1728. #endif
  1729.     OS_ENTER_CRITICAL();
  1730.     ptcb = OSTCBFreeList;                                  /* Get a free TCB from the free TCB list    */
  1731.     if (ptcb != (OS_TCB *)0) {
  1732.         OSTCBFreeList            = ptcb->OSTCBNext;        /* Update pointer to free TCB list          */
  1733.         OS_EXIT_CRITICAL();
  1734.         ptcb->OSTCBStkPtr        = ptos;                   /* Load Stack pointer in TCB                */
  1735.         ptcb->OSTCBPrio          = prio;                   /* Load task priority into TCB              */
  1736.         ptcb->OSTCBStat          = OS_STAT_RDY;            /* Task is ready to run                     */
  1737.         ptcb->OSTCBStatPend      = OS_STAT_PEND_OK;        /* Clear pend status                        */
  1738.         ptcb->OSTCBDly           = 0;                      /* Task is not delayed                      */
  1739. #if OS_TASK_CREATE_EXT_EN > 0
  1740.         ptcb->OSTCBExtPtr        = pext;                   /* Store pointer to TCB extension           */
  1741.         ptcb->OSTCBStkSize       = stk_size;               /* Store stack size                         */
  1742.         ptcb->OSTCBStkBottom     = pbos;                   /* Store pointer to bottom of stack         */
  1743.         ptcb->OSTCBOpt           = opt;                    /* Store task options                       */
  1744.         ptcb->OSTCBId            = id;                     /* Store task ID                            */
  1745. #else
  1746.         pext                     = pext;                   /* Prevent compiler warning if not used     */
  1747.         stk_size                 = stk_size;
  1748.         pbos                     = pbos;
  1749.         opt                      = opt;
  1750.         id                       = id;
  1751. #endif
  1752. #if OS_TASK_DEL_EN > 0
  1753.         ptcb->OSTCBDelReq        = OS_ERR_NONE;
  1754. #endif
  1755. #if OS_LOWEST_PRIO <= 63
  1756.         ptcb->OSTCBY             = (INT8U)(prio >> 3);          /* Pre-compute X, Y, BitX and BitY     */
  1757.         ptcb->OSTCBX             = (INT8U)(prio & 0x07);
  1758.         ptcb->OSTCBBitY          = (INT8U)(1 << ptcb->OSTCBY);
  1759.         ptcb->OSTCBBitX          = (INT8U)(1 << ptcb->OSTCBX);
  1760. #else
  1761.         ptcb->OSTCBY             = (INT8U)((prio >> 4) & 0xFF); /* Pre-compute X, Y, BitX and BitY     */
  1762.         ptcb->OSTCBX             = (INT8U) (prio & 0x0F);
  1763.         ptcb->OSTCBBitY          = (INT16U)(1 << ptcb->OSTCBY);
  1764.         ptcb->OSTCBBitX          = (INT16U)(1 << ptcb->OSTCBX);
  1765. #endif
  1766. #if (OS_EVENT_EN)
  1767.         ptcb->OSTCBEventPtr      = (OS_EVENT  *)0;         /* Task is not pending on an  event         */
  1768. #if (OS_EVENT_MULTI_EN > 0)
  1769.         ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0;         /* Task is not pending on any events        */
  1770. #endif
  1771. #endif
  1772. #if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
  1773.         ptcb->OSTCBFlagNode  = (OS_FLAG_NODE *)0;          /* Task is not pending on an event flag     */
  1774. #endif
  1775. #if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
  1776.         ptcb->OSTCBMsg       = (void *)0;                  /* No message received                      */
  1777. #endif
  1778. #if OS_TASK_PROFILE_EN > 0
  1779.         ptcb->OSTCBCtxSwCtr    = 0L;                       /* Initialize profiling variables           */
  1780.         ptcb->OSTCBCyclesStart = 0L;
  1781.         ptcb->OSTCBCyclesTot   = 0L;
  1782.         ptcb->OSTCBStkBase     = (OS_STK *)0;
  1783.         ptcb->OSTCBStkUsed     = 0L;
  1784. #endif
  1785. #if OS_TASK_NAME_EN > 0
  1786.         ptcb->OSTCBTaskName    = "?";                      /* Unknown name at task creation            */
  1787. #endif
  1788. #if OS_TASK_REG_TBL_SIZE > 0                               /* Initialize the task variables            */
  1789.         for (i = 0; i < OS_TASK_REG_TBL_SIZE; i++) {
  1790.             ptcb->OSTCBRegTbl[i] = 0;
  1791.         }
  1792. #endif        
  1793.         OSTCBInitHook(ptcb);
  1794.         OSTaskCreateHook(ptcb);                            /* Call user defined hook                   */
  1795.         OS_ENTER_CRITICAL();
  1796.         OSTCBPrioTbl[prio] = ptcb;
  1797.         ptcb->OSTCBNext    = OSTCBList;                    /* Link into TCB chain                      */
  1798.         ptcb->OSTCBPrev    = (OS_TCB *)0;
  1799.         if (OSTCBList != (OS_TCB *)0) {
  1800.             OSTCBList->OSTCBPrev = ptcb;
  1801.         }
  1802.         OSTCBList               = ptcb;
  1803.         OSRdyGrp               |= ptcb->OSTCBBitY;         /* Make task ready to run                   */
  1804.         OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  1805.         OSTaskCtr++;                                       /* Increment the #tasks counter             */
  1806.         OS_EXIT_CRITICAL();
  1807.         return (OS_ERR_NONE);
  1808.     }
  1809.     OS_EXIT_CRITICAL();
  1810.     return (OS_ERR_TASK_NO_MORE_TCB);
  1811. }