os_core.c
上传用户:yj_qqy
上传日期:2017-01-28
资源大小:2911k
文件大小:86k
源码类别:

uCOS

开发平台:

C/C++

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