os_core.c
上传用户:jingkewang
上传日期:2013-04-11
资源大小:917k
文件大小:67k
源码类别:

uCOS

开发平台:

Visual C++

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