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

微处理器开发

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                             CORE FUNCTIONS
  6. *
  7. *                          (c) Copyright 1992-2001, Jean J. Labrosse, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File : OS_CORE.C
  11. * By   : Jean J. Labrosse
  12. *********************************************************************************************************
  13. */
  14. #ifndef  OS_MASTER_FILE
  15. #define  OS_GLOBALS
  16. #include "includes.h"
  17. #endif
  18. /*
  19. *********************************************************************************************************
  20. *                              MAPPING TABLE TO MAP BIT POSITION TO BIT MASK
  21. *
  22. * Note: Index into table is desired bit position, 0..7
  23. *       Indexed value corresponds to bit mask
  24. *********************************************************************************************************
  25. */
  26. INT8U  const  OSMapTbl[]   = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
  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[] = {
  36.     0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  37.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  38.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  39.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  40.     6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  41.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  42.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  43.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  44.     7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  45.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  46.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  47.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  48.     6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  49.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  50.     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  51.     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
  52. };
  53. /*$PAGE*/
  54. /*
  55. *********************************************************************************************************
  56. *                                             INITIALIZATION
  57. *
  58. * Description: This function is used to initialize the internals of uC/OS-II and MUST be called prior to
  59. *              creating any uC/OS-II object and, prior to calling OSStart().
  60. *
  61. * Arguments  : none
  62. *
  63. * Returns    : none
  64. *********************************************************************************************************
  65. */
  66. void  OSInit (void)
  67. {
  68.     INT16U     i;
  69.     INT8U     *prdytbl;
  70.     OS_TCB    *ptcb1;
  71.     OS_TCB    *ptcb2;
  72. #if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 1)
  73.     OS_EVENT  *pevent1;
  74.     OS_EVENT  *pevent2;
  75. #endif
  76. #if OS_VERSION >= 204
  77.     OSInitHookBegin();                                           /* Call port specific initialization code   */
  78. #endif
  79. #if OS_TIME_GET_SET_EN > 0   
  80.     OSTime        = 0L;                                          /* Clear the 32-bit system clock            */
  81. #endif
  82.     OSIntNesting  = 0;                                           /* Clear the interrupt nesting counter      */
  83.     OSLockNesting = 0;                                           /* Clear the scheduling lock counter        */
  84.     OSTaskCtr     = 0;                                           /* Clear the number of tasks                */
  85.     OSRunning     = FALSE;                                       /* Indicate that multitasking not started   */
  86.     OSIdleCtr     = 0L;                                          /* Clear the 32-bit idle counter            */
  87. #if (OS_TASK_STAT_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
  88.     OSIdleCtrRun  = 0L;
  89.     OSIdleCtrMax  = 0L;
  90.     OSStatRdy     = FALSE;                                       /* Statistic task is not ready              */
  91. #endif
  92.     OSCtxSwCtr    = 0;                                           /* Clear the context switch counter         */
  93.     OSRdyGrp      = 0x00;                                        /* Clear the ready list                     */
  94.     prdytbl       = &OSRdyTbl[0];
  95.     for (i = 0; i < OS_RDY_TBL_SIZE; i++) {
  96.         *prdytbl++ = 0x00;
  97.     }
  98.     OSPrioCur     = 0;
  99.     OSPrioHighRdy = 0;
  100.     OSTCBHighRdy  = (OS_TCB *)0;                                 /* TCB Initialization                       */
  101.     OSTCBCur      = (OS_TCB *)0;
  102.     OSTCBList     = (OS_TCB *)0;
  103.     for (i = 0; i < (OS_LOWEST_PRIO + 1); i++) {                 /* Clear the priority table                 */
  104.         OSTCBPrioTbl[i] = (OS_TCB *)0;
  105.     }
  106.     ptcb1 = &OSTCBTbl[0];
  107.     ptcb2 = &OSTCBTbl[1];
  108.     for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) {  /* Init. list of free TCBs                  */
  109.         ptcb1->OSTCBNext = ptcb2;
  110.         ptcb1++;
  111.         ptcb2++;
  112.     }
  113.     ptcb1->OSTCBNext = (OS_TCB *)0;                              /* Last OS_TCB                              */
  114.     OSTCBFreeList    = &OSTCBTbl[0];
  115. #if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 0)
  116.     #if OS_MAX_EVENTS == 1                                       
  117.     OSEventFreeList              = &OSEventTbl[0];               /* Only have ONE event control block        */
  118.     OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED;
  119.     OSEventFreeList->OSEventPtr  = (OS_EVENT *)0;
  120.     #else
  121.     pevent1 = &OSEventTbl[0];
  122.     pevent2 = &OSEventTbl[1];
  123.     for (i = 0; i < (OS_MAX_EVENTS - 1); i++) {                  /* Init. list of free EVENT control blocks  */
  124.         pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
  125.         pevent1->OSEventPtr  = pevent2;
  126.         pevent1++;
  127.         pevent2++;
  128.     }
  129.     pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
  130.     pevent1->OSEventPtr  = (OS_EVENT *)0;
  131.     OSEventFreeList      = &OSEventTbl[0];
  132.     #endif
  133. #endif
  134. #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
  135.     OS_FlagInit();                                               /* Initialize the event flag structures     */
  136. #endif
  137. #if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
  138.     OS_QInit();                                                  /* Initialize the message queue structures  */
  139. #endif
  140. #if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
  141.     OS_MemInit();                                                /* Initialize the memory manager            */
  142. #endif
  143.     /* ------------------------------------- CREATION OF 'IDLE' TASK --------------------------------------- */
  144. #if OS_TASK_CREATE_EXT_EN > 0
  145.     #if OS_STK_GROWTH == 1
  146.     (void)OSTaskCreateExt(OS_TaskIdle,
  147.                           (void *)0,                                 /* No arguments passed to OS_TaskIdle() */
  148.                           &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /* Set Top-Of-Stack                     */
  149.                           OS_IDLE_PRIO,                              /* Lowest priority level                */
  150.                           OS_TASK_IDLE_ID,
  151.                           &OSTaskIdleStk[0],                         /* Set Bottom-Of-Stack                  */
  152.                           OS_TASK_IDLE_STK_SIZE,
  153.                           (void *)0,                                 /* No TCB extension                     */
  154.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack  */
  155.     #else
  156.     (void)OSTaskCreateExt(OS_TaskIdle,
  157.                           (void *)0,                                 /* No arguments passed to OS_TaskIdle() */
  158.                           &OSTaskIdleStk[0],                         /* Set Top-Of-Stack                     */
  159.                           OS_IDLE_PRIO,                              /* Lowest priority level                */
  160.                           OS_TASK_IDLE_ID,
  161.                           &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /* Set Bottom-Of-Stack                  */
  162.                           OS_TASK_IDLE_STK_SIZE,
  163.                           (void *)0,                                 /* No TCB extension                     */
  164.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack  */
  165.     #endif
  166. #else
  167.     #if OS_STK_GROWTH == 1
  168.     (void)OSTaskCreate(OS_TaskIdle,
  169.                        (void *)0,
  170.                        &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],
  171.                        OS_IDLE_PRIO);
  172.     #else
  173.     (void)OSTaskCreate(OS_TaskIdle,
  174.                        (void *)0,
  175.                        &OSTaskIdleStk[0],
  176.                        OS_IDLE_PRIO);
  177.     #endif
  178. #endif
  179.     /* ------------------------------- CREATION OF 'STATISTIC' TASK ---------------------------------- */
  180. #if OS_TASK_STAT_EN > 0
  181.     #if OS_TASK_CREATE_EXT_EN > 0
  182.         #if OS_STK_GROWTH == 1
  183.         (void)OSTaskCreateExt(OS_TaskStat,
  184.                               (void *)0,                                   /* No args passed to OS_TaskStat()*/
  185.                               &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Top-Of-Stack               */
  186.                               OS_STAT_PRIO,                                /* One higher than the idle task  */
  187.                               OS_TASK_STAT_ID,
  188.                               &OSTaskStatStk[0],                           /* Set Bottom-Of-Stack            */
  189.                               OS_TASK_STAT_STK_SIZE,
  190.                               (void *)0,                                   /* No TCB extension               */
  191.                               OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
  192.         #else
  193.         (void)OSTaskCreateExt(OS_TaskStat,
  194.                               (void *)0,                                   /* No args passed to OS_TaskStat()*/
  195.                               &OSTaskStatStk[0],                           /* Set Top-Of-Stack               */
  196.                               OS_STAT_PRIO,                                /* One higher than the idle task  */
  197.                               OS_TASK_STAT_ID,
  198.                               &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Bottom-Of-Stack            */
  199.                               OS_TASK_STAT_STK_SIZE,
  200.                               (void *)0,                                   /* No TCB extension               */
  201.                               OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
  202.         #endif
  203.     #else
  204.         #if OS_STK_GROWTH == 1
  205.         (void)OSTaskCreate(OS_TaskStat,
  206.                            (void *)0,                                      /* No args passed to OS_TaskStat()*/
  207.                            &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],      /* Set Top-Of-Stack               */
  208.                            OS_STAT_PRIO);                                  /* One higher than the idle task  */
  209.         #else
  210.         (void)OSTaskCreate(OS_TaskStat,
  211.                            (void *)0,                                      /* No args passed to OS_TaskStat()*/
  212.                            &OSTaskStatStk[0],                              /* Set Top-Of-Stack               */
  213.                            OS_STAT_PRIO);                                  /* One higher than the idle task  */
  214.         #endif
  215.     #endif
  216. #endif
  217. #if OS_VERSION >= 204
  218.     OSInitHookEnd();                                                       /* Call port specific init. code  */
  219. #endif
  220. }
  221. /*$PAGE*/
  222. /*
  223. *********************************************************************************************************
  224. *                                              ENTER ISR
  225. *
  226. * Description: This function is used to notify uC/OS-II that you are about to service an interrupt
  227. *              service routine (ISR).  This allows uC/OS-II to keep track of interrupt nesting and thus
  228. *              only perform rescheduling at the last nested ISR.
  229. *
  230. * Arguments  : none
  231. *
  232. * Returns    : none
  233. *
  234. * Notes      : 1) Your ISR can directly increment OSIntNesting without calling this function because
  235. *                 OSIntNesting has been declared 'global'.  You MUST, however, be sure that the increment
  236. *                 is performed 'indivisibly' by your processor to ensure proper access to this critical
  237. *                 resource.
  238. *              2) You MUST still call OSIntExit() even though you increment OSIntNesting directly.
  239. *              3) You MUST invoke OSIntEnter() and OSIntExit() in pair.  In other words, for every call
  240. *                 to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the
  241. *                 end of the ISR.
  242. *********************************************************************************************************
  243. */
  244. void  OSIntEnter (void)
  245. {
  246. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  247.     OS_CPU_SR  cpu_sr;
  248. #endif    
  249.     
  250.     
  251.     OS_ENTER_CRITICAL();
  252.     if (OSIntNesting < 255) {
  253.         OSIntNesting++;                          /* Increment ISR nesting level                        */
  254.     }
  255.     OS_EXIT_CRITICAL();
  256. }
  257. /*$PAGE*/
  258. /*
  259. *********************************************************************************************************
  260. *                                               EXIT ISR
  261. *
  262. * Description: This function is used to notify uC/OS-II that you have completed serviving an ISR.  When
  263. *              the last nested ISR has completed, uC/OS-II will call the scheduler to determine whether
  264. *              a new, high-priority task, is ready to run.
  265. *
  266. * Arguments  : none
  267. *
  268. * Returns    : none
  269. *
  270. * Notes      : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair.  In other words, for every call
  271. *                 to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the
  272. *                 end of the ISR.
  273. *              2) Rescheduling is prevented when the scheduler is locked (see OSSchedLock())
  274. *********************************************************************************************************
  275. */
  276. void  OSIntExit (void)
  277. {
  278. #if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
  279.     OS_CPU_SR  cpu_sr;
  280. #endif
  281.     
  282.     
  283.     OS_ENTER_CRITICAL();
  284.     if (OSIntNesting > 0) {                            /* Prevent OSIntNesting from wrapping           */
  285.         OSIntNesting--;
  286.     }
  287.     if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Reschedule only if all ISRs complete ...     */
  288.         OSIntExitY    = OSUnMapTbl[OSRdyGrp];          /* ... and not locked.                          */
  289.         OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
  290.         if (OSPrioHighRdy != OSPrioCur) {              /* No Ctx Sw if current task is highest rdy     */
  291.             OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];
  292.             OSCtxSwCtr++;                              /* Keep track of the number of context switches */
  293.             OSIntCtxSw();                              /* Perform interrupt level context switch       */
  294.         }
  295.     }
  296.     OS_EXIT_CRITICAL();
  297. }
  298. /*$PAGE*/
  299. /*
  300. *********************************************************************************************************
  301. *                                          PREVENT SCHEDULING
  302. *
  303. * Description: This function is used to prevent rescheduling to take place.  This allows your application
  304. *              to prevent context switches until you are ready to permit context switching.
  305. *
  306. * Arguments  : none
  307. *
  308. * Returns    : none
  309. *
  310. * Notes      : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair.  In other words, for every
  311. *                 call to OSSchedLock() you MUST have a call to OSSchedUnlock().
  312. *********************************************************************************************************
  313. */
  314. #if OS_SCHED_LOCK_EN > 0
  315. void  OSSchedLock (void)
  316. {
  317. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  318.     OS_CPU_SR  cpu_sr;
  319. #endif    
  320.     
  321.     
  322.     if (OSRunning == TRUE) {                     /* Make sure multitasking is running                  */
  323.         OS_ENTER_CRITICAL();
  324.         if (OSLockNesting < 255) {               /* Prevent OSLockNesting from wrapping back to 0      */
  325.             OSLockNesting++;                     /* Increment lock nesting level                       */
  326.         }
  327.         OS_EXIT_CRITICAL();
  328.     }
  329. }
  330. #endif    
  331. /*$PAGE*/
  332. /*
  333. *********************************************************************************************************
  334. *                                          ENABLE SCHEDULING
  335. *
  336. * Description: This function is used to re-allow rescheduling.
  337. *
  338. * Arguments  : none
  339. *
  340. * Returns    : none
  341. *
  342. * Notes      : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair.  In other words, for every
  343. *                 call to OSSchedLock() you MUST have a call to OSSchedUnlock().
  344. *********************************************************************************************************
  345. */
  346. #if OS_SCHED_LOCK_EN > 0
  347. void  OSSchedUnlock (void)
  348. {
  349. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  350.     OS_CPU_SR  cpu_sr;
  351. #endif    
  352.     
  353.     
  354.     if (OSRunning == TRUE) {                                   /* Make sure multitasking is running    */
  355.         OS_ENTER_CRITICAL();
  356.         if (OSLockNesting > 0) {                               /* Do not decrement if already 0        */
  357.             OSLockNesting--;                                   /* Decrement lock nesting level         */
  358.             if ((OSLockNesting == 0) && (OSIntNesting == 0)) { /* See if sched. enabled and not an ISR */
  359.                 OS_EXIT_CRITICAL();
  360.                 OS_Sched();                                    /* See if a HPT is ready                */
  361.             } else {
  362.                 OS_EXIT_CRITICAL();
  363.             }
  364.         } else {
  365.             OS_EXIT_CRITICAL();
  366.         }
  367.     }
  368. }
  369. #endif    
  370. /*$PAGE*/
  371. /*
  372. *********************************************************************************************************
  373. *                                          START MULTITASKING
  374. *
  375. * Description: This function is used to start the multitasking process which lets uC/OS-II manages the
  376. *              task that you have created.  Before you can call OSStart(), you MUST have called OSInit()
  377. *              and you MUST have created at least one task.
  378. *
  379. * Arguments  : none
  380. *
  381. * Returns    : none
  382. *
  383. * Note       : OSStartHighRdy() MUST:
  384. *                 a) Call OSTaskSwHook() then,
  385. *                 b) Set OSRunning to TRUE.
  386. *********************************************************************************************************
  387. */
  388. void  OSStart (void)
  389. {
  390.     INT8U y;
  391.     INT8U x;
  392.     if (OSRunning == FALSE) {
  393.         y             = OSUnMapTbl[OSRdyGrp];        /* Find highest priority's task priority number   */
  394.         x             = OSUnMapTbl[OSRdyTbl[y]];
  395.         OSPrioHighRdy = (INT8U)((y << 3) + x);
  396.         OSPrioCur     = OSPrioHighRdy;
  397.         OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run    */
  398.         OSTCBCur      = OSTCBHighRdy;
  399.         OSStartHighRdy();                            /* Execute target specific code to start task     */
  400.     }
  401. }
  402. /*$PAGE*/
  403. /*
  404. *********************************************************************************************************
  405. *                                        STATISTICS INITIALIZATION
  406. *
  407. * Description: This function is called by your application to establish CPU usage by first determining
  408. *              how high a 32-bit counter would count to in 1 second if no other tasks were to execute
  409. *              during that time.  CPU usage is then determined by a low priority task which keeps track
  410. *              of this 32-bit counter every second but this time, with other tasks running.  CPU usage is
  411. *              determined by:
  412. *
  413. *                                             OSIdleCtr
  414. *                 CPU Usage (%) = 100 * (1 - ------------)
  415. *                                            OSIdleCtrMax
  416. *
  417. * Arguments  : none
  418. *
  419. * Returns    : none
  420. *********************************************************************************************************
  421. */
  422. #if OS_TASK_STAT_EN > 0
  423. void  OSStatInit (void)
  424. {
  425. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  426.     OS_CPU_SR  cpu_sr;
  427. #endif    
  428.     
  429.     
  430.     OSTimeDly(2);                                /* Synchronize with clock tick                        */
  431.     OS_ENTER_CRITICAL();
  432.     OSIdleCtr    = 0L;                           /* Clear idle counter                                 */
  433.     OS_EXIT_CRITICAL();
  434.     OSTimeDly(OS_TICKS_PER_SEC);                 /* Determine MAX. idle counter value for 1 second     */
  435.     OS_ENTER_CRITICAL();
  436.     OSIdleCtrMax = OSIdleCtr;                    /* Store maximum idle counter count in 1 second       */
  437.     OSStatRdy    = TRUE;
  438.     OS_EXIT_CRITICAL();
  439. }
  440. #endif
  441. /*$PAGE*/
  442. /*
  443. *********************************************************************************************************
  444. *                                         PROCESS SYSTEM TICK
  445. *
  446. * Description: This function is used to signal to uC/OS-II the occurrence of a 'system tick' (also known
  447. *              as a 'clock tick').  This function should be called by the ticker ISR but, can also be
  448. *              called by a high priority task.
  449. *
  450. * Arguments  : none
  451. *
  452. * Returns    : none
  453. *********************************************************************************************************
  454. */
  455. void  OSTimeTick (void)
  456. {
  457. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  458.     OS_CPU_SR  cpu_sr;
  459. #endif    
  460.     OS_TCB    *ptcb;
  461.     OSTimeTickHook();                                      /* Call user definable hook                 */
  462. #if OS_TIME_GET_SET_EN > 0   
  463.     OS_ENTER_CRITICAL();                                   /* Update the 32-bit tick counter           */
  464.     OSTime++;
  465.     OS_EXIT_CRITICAL();
  466. #endif    
  467.     ptcb = OSTCBList;                                      /* Point at first TCB in TCB list           */
  468.     while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {              /* Go through all TCBs in TCB list          */
  469.         OS_ENTER_CRITICAL();
  470.         if (ptcb->OSTCBDly != 0) {                         /* Delayed or waiting for event with TO     */
  471.             if (--ptcb->OSTCBDly == 0) {                   /* Decrement nbr of ticks to end of delay   */
  472.                 if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == 0x00) {   /* Is task suspended?             */
  473.                     OSRdyGrp               |= ptcb->OSTCBBitY; /* No,  Make task Rdy to Run (timed out)*/
  474.                     OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  475.                 } else {                                       /* Yes, Leave 1 tick to prevent ...     */
  476.                     ptcb->OSTCBDly = 1;                        /* ... loosing the task when the ...    */
  477.                 }                                              /* ... suspension is removed.           */
  478.             }
  479.         }
  480.         ptcb = ptcb->OSTCBNext;                                /* Point at next TCB in TCB list        */
  481.         OS_EXIT_CRITICAL();
  482.     }
  483. }
  484. /*$PAGE*/
  485. /*
  486. *********************************************************************************************************
  487. *                                             GET VERSION
  488. *
  489. * Description: This function is used to return the version number of uC/OS-II.  The returned value
  490. *              corresponds to uC/OS-II's version number multiplied by 100.  In other words, version 2.00
  491. *              would be returned as 200.
  492. *
  493. * Arguments  : none
  494. *
  495. * Returns    : the version number of uC/OS-II multiplied by 100.
  496. *********************************************************************************************************
  497. */
  498. INT16U  OSVersion (void)
  499. {
  500.     return (OS_VERSION);
  501. }
  502. /*$PAGE*/
  503. /*
  504. *********************************************************************************************************
  505. *                                            DUMMY FUNCTION
  506. *
  507. * Description: This function doesn't do anything.  It is called by OSTaskDel().
  508. *
  509. * Arguments  : none
  510. *
  511. * Returns    : none
  512. *********************************************************************************************************
  513. */
  514. #if OS_TASK_DEL_EN > 0
  515. void  OS_Dummy (void)
  516. {
  517. }
  518. #endif
  519. /*$PAGE*/
  520. /*
  521. *********************************************************************************************************
  522. *                             MAKE TASK READY TO RUN BASED ON EVENT OCCURING
  523. *
  524. * Description: This function is called by other uC/OS-II services and is used to ready a task that was
  525. *              waiting for an event to occur.
  526. *
  527. * Arguments  : pevent    is a pointer to the event control block corresponding to the event.
  528. *
  529. *              msg       is a pointer to a message.  This pointer is used by message oriented services
  530. *                        such as MAILBOXEs and QUEUEs.  The pointer is not used when called by other
  531. *                        service functions.
  532. *
  533. *              msk       is a mask that is used to clear the status byte of the TCB.  For example,
  534. *                        OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc.
  535. *
  536. * Returns    : none
  537. *
  538. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  539. *********************************************************************************************************
  540. */
  541. #if OS_EVENT_EN > 0
  542. INT8U  OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
  543. {
  544.     OS_TCB *ptcb;
  545.     INT8U   x;
  546.     INT8U   y;
  547.     INT8U   bitx;
  548.     INT8U   bity;
  549.     INT8U   prio;
  550.     y    = OSUnMapTbl[pevent->OSEventGrp];            /* Find highest prio. task waiting for message   */
  551.     bity = OSMapTbl[y];
  552.     x    = OSUnMapTbl[pevent->OSEventTbl[y]];
  553.     bitx = OSMapTbl[x];
  554.     prio = (INT8U)((y << 3) + x);                     /* Find priority of task getting the msg         */
  555.     if ((pevent->OSEventTbl[y] &= ~bitx) == 0x00) {   /* Remove this task from the waiting list        */
  556.         pevent->OSEventGrp &= ~bity;                  /* Clr group bit if this was only task pending   */
  557.     }
  558.     ptcb                 =  OSTCBPrioTbl[prio];       /* Point to this task's OS_TCB                   */
  559.     ptcb->OSTCBDly       =  0;                        /* Prevent OSTimeTick() from readying task       */
  560.     ptcb->OSTCBEventPtr  = (OS_EVENT *)0;             /* Unlink ECB from this task                     */
  561. #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
  562.     ptcb->OSTCBMsg       = msg;                       /* Send message directly to waiting task         */
  563. #else
  564.     msg                  = msg;                       /* Prevent compiler warning if not used          */
  565. #endif
  566.     ptcb->OSTCBStat     &= ~msk;                      /* Clear bit associated with event type          */
  567.     if (ptcb->OSTCBStat == OS_STAT_RDY) {             /* See if task is ready (could be susp'd)        */
  568.         OSRdyGrp        |=  bity;                     /* Put task in the ready to run list             */
  569.         OSRdyTbl[y]     |=  bitx;
  570.     }
  571.     return (prio);
  572. }
  573. #endif
  574. /*$PAGE*/
  575. /*
  576. *********************************************************************************************************
  577. *                                   MAKE TASK WAIT FOR EVENT TO OCCUR
  578. *
  579. * Description: This function is called by other uC/OS-II services to suspend a task because an event has
  580. *              not occurred.
  581. *
  582. * Arguments  : pevent   is a pointer to the event control block for which the task will be waiting for.
  583. *
  584. * Returns    : none
  585. *
  586. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  587. *********************************************************************************************************
  588. */
  589. #if OS_EVENT_EN > 0
  590. void  OS_EventTaskWait (OS_EVENT *pevent)
  591. {
  592.     OSTCBCur->OSTCBEventPtr = pevent;            /* Store pointer to event control block in TCB        */
  593.     if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {   /* Task no longer ready      */
  594.         OSRdyGrp &= ~OSTCBCur->OSTCBBitY;        /* Clear event grp bit if this was only task pending  */
  595.     }
  596.     pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;          /* Put task in waiting list  */
  597.     pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;
  598. }
  599. #endif
  600. /*$PAGE*/
  601. /*
  602. *********************************************************************************************************
  603. *                              MAKE TASK READY TO RUN BASED ON EVENT TIMEOUT
  604. *
  605. * Description: This function is called by other uC/OS-II services to make a task ready to run because a
  606. *              timeout occurred.
  607. *
  608. * Arguments  : pevent   is a pointer to the event control block which is readying a task.
  609. *
  610. * Returns    : none
  611. *
  612. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  613. *********************************************************************************************************
  614. */
  615. #if OS_EVENT_EN > 0
  616. void  OS_EventTO (OS_EVENT *pevent)
  617. {
  618.     if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {
  619.         pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
  620.     }
  621.     OSTCBCur->OSTCBStat     = OS_STAT_RDY;       /* Set status to ready                                */
  622.     OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;     /* No longer waiting for event                        */
  623. }
  624. #endif
  625. /*$PAGE*/
  626. /*
  627. *********************************************************************************************************
  628. *                                 INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
  629. *
  630. * Description: This function is called by other uC/OS-II services to initialize the event wait list.
  631. *
  632. * Arguments  : pevent    is a pointer to the event control block allocated to the event.
  633. *
  634. * Returns    : none
  635. *
  636. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  637. *********************************************************************************************************
  638. */
  639. #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)
  640. void  OS_EventWaitListInit (OS_EVENT *pevent)
  641. {
  642.     INT8U  *ptbl;
  643.     pevent->OSEventGrp = 0x00;                   /* No task waiting on event                           */
  644.     ptbl               = &pevent->OSEventTbl[0];
  645. #if OS_EVENT_TBL_SIZE > 0
  646.     *ptbl++            = 0x00;
  647. #endif
  648. #if OS_EVENT_TBL_SIZE > 1
  649.     *ptbl++            = 0x00;
  650. #endif
  651. #if OS_EVENT_TBL_SIZE > 2
  652.     *ptbl++            = 0x00;
  653. #endif
  654. #if OS_EVENT_TBL_SIZE > 3
  655.     *ptbl++            = 0x00;
  656. #endif
  657. #if OS_EVENT_TBL_SIZE > 4
  658.     *ptbl++            = 0x00;
  659. #endif
  660. #if OS_EVENT_TBL_SIZE > 5
  661.     *ptbl++            = 0x00;
  662. #endif
  663. #if OS_EVENT_TBL_SIZE > 6
  664.     *ptbl++            = 0x00;
  665. #endif
  666. #if OS_EVENT_TBL_SIZE > 7
  667.     *ptbl              = 0x00;
  668. #endif
  669. }
  670. #endif
  671. /*$PAGE*/
  672. /*
  673. *********************************************************************************************************
  674. *                                              SCHEDULER
  675. *
  676. * Description: This function is called by other uC/OS-II services to determine whether a new, high
  677. *              priority task has been made ready to run.  This function is invoked by TASK level code
  678. *              and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling).
  679. *
  680. * Arguments  : none
  681. *
  682. * Returns    : none
  683. *
  684. * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
  685. *              2) Rescheduling is prevented when the scheduler is locked (see OSSchedLock())
  686. *********************************************************************************************************
  687. */
  688. void  OS_Sched (void)
  689. {
  690. #if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
  691.     OS_CPU_SR  cpu_sr;
  692. #endif    
  693.     INT8U      y;
  694.     OS_ENTER_CRITICAL();
  695.     if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked    */
  696.         y             = OSUnMapTbl[OSRdyGrp];          /* Get pointer to HPT ready to run              */
  697.         OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
  698.         if (OSPrioHighRdy != OSPrioCur) {              /* No Ctx Sw if current task is highest rdy     */
  699.             OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
  700.             OSCtxSwCtr++;                              /* Increment context switch counter             */
  701.             OS_TASK_SW();                              /* Perform a context switch                     */
  702.         }
  703.     }
  704.     OS_EXIT_CRITICAL();
  705. }
  706. /*$PAGE*/
  707. /*
  708. *********************************************************************************************************
  709. *                                              IDLE TASK
  710. *
  711. * Description: This task is internal to uC/OS-II and executes whenever no other higher priority tasks
  712. *              executes because they are ALL waiting for event(s) to occur.
  713. *
  714. * Arguments  : none
  715. *
  716. * Returns    : none
  717. *
  718. * Note(s)    : 1) OSTaskIdleHook() is called after the critical section to ensure that interrupts will be
  719. *                 enabled for at least a few instructions.  On some processors (ex. Philips XA), enabling
  720. *                 and then disabling interrupts didn't allow the processor enough time to have interrupts
  721. *                 enabled before they were disabled again.  uC/OS-II would thus never recognize
  722. *                 interrupts.
  723. *              2) This hook has been added to allow you to do such things as STOP the CPU to conserve 
  724. *                 power.
  725. *********************************************************************************************************
  726. */
  727. void  OS_TaskIdle (void *pdata)
  728. {
  729. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  730.     OS_CPU_SR  cpu_sr;
  731. #endif    
  732.     
  733.     
  734.     pdata = pdata;                               /* Prevent compiler warning for not using 'pdata'     */
  735.     for (;;) {
  736.         OS_ENTER_CRITICAL();
  737.         OSIdleCtr++;
  738.         OS_EXIT_CRITICAL();
  739.         OSTaskIdleHook();                        /* Call user definable HOOK                           */
  740.  
  741.      }
  742. }
  743. /*$PAGE*/
  744. /*
  745. *********************************************************************************************************
  746. *                                            STATISTICS TASK
  747. *
  748. * Description: This task is internal to uC/OS-II and is used to compute some statistics about the
  749. *              multitasking environment.  Specifically, OS_TaskStat() computes the CPU usage.
  750. *              CPU usage is determined by:
  751. *
  752. *                                          OSIdleCtr
  753. *                 OSCPUUsage = 100 * (1 - ------------)     (units are in %)
  754. *                                         OSIdleCtrMax
  755. *
  756. * Arguments  : pdata     this pointer is not used at this time.
  757. *
  758. * Returns    : none
  759. *
  760. * Notes      : 1) This task runs at a priority level higher than the idle task.  In fact, it runs at the
  761. *                 next higher priority, OS_IDLE_PRIO-1.
  762. *              2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0.
  763. *              3) We delay for 5 seconds in the beginning to allow the system to reach steady state and
  764. *                 have all other tasks created before we do statistics.  You MUST have at least a delay
  765. *                 of 2 seconds to allow for the system to establish the maximum value for the idle
  766. *                 counter.
  767. *********************************************************************************************************
  768. */
  769. #if OS_TASK_STAT_EN > 0
  770. void  OS_TaskStat (void *pdata)
  771. {
  772. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  773.     OS_CPU_SR  cpu_sr;
  774. #endif    
  775.     INT32U     run;
  776.     INT8S      usage;
  777.     pdata = pdata;                               /* Prevent compiler warning for not using 'pdata'     */
  778.     while (OSStatRdy == FALSE) {
  779.         OSTimeDly(2 * OS_TICKS_PER_SEC);         /* Wait until statistic task is ready                 */
  780.     }
  781.     for (;;) {
  782.         OS_ENTER_CRITICAL();
  783.         OSIdleCtrRun = OSIdleCtr;                /* Obtain the of the idle counter for the past second */
  784.         run          = OSIdleCtr;
  785.         OSIdleCtr    = 0L;                       /* Reset the idle counter for the next second         */
  786.         OS_EXIT_CRITICAL();
  787.         if (OSIdleCtrMax > 0L) {
  788.             usage = (INT8S)(100L - 100L * run / OSIdleCtrMax);
  789.             if (usage >= 0) {                    /* Make sure we don't have a negative percentage      */
  790.                 OSCPUUsage = usage;
  791.             } else {
  792.                 OSCPUUsage = 0;
  793.             }
  794.         } else {
  795.             OSCPUUsage = 0;
  796.         }
  797.         OSTaskStatHook();                        /* Invoke user definable hook                         */
  798.         OSTimeDly(OS_TICKS_PER_SEC);             /* Accumulate OSIdleCtr for the next second           */
  799.     }
  800. }
  801. #endif
  802. /*$PAGE*/
  803. /*
  804. *********************************************************************************************************
  805. *                                            INITIALIZE TCB
  806. *
  807. * Description: This function is internal to uC/OS-II and is used to initialize a Task Control Block when
  808. *              a task is created (see OSTaskCreate() and OSTaskCreateExt()).
  809. *
  810. * Arguments  : prio          is the priority of the task being created
  811. *
  812. *              ptos          is a pointer to the task's top-of-stack assuming that the CPU registers
  813. *                            have been placed on the stack.  Note that the top-of-stack corresponds to a
  814. *                            'high' memory location is OS_STK_GROWTH is set to 1 and a 'low' memory
  815. *                            location if OS_STK_GROWTH is set to 0.  Note that stack growth is CPU
  816. *                            specific.
  817. *
  818. *              pbos          is a pointer to the bottom of stack.  A NULL pointer is passed if called by
  819. *                            'OSTaskCreate()'.
  820. *
  821. *              id            is the task's ID (0..65535)
  822. *
  823. *              stk_size      is the size of the stack (in 'stack units').  If the stack units are INT8Us
  824. *                            then, 'stk_size' contains the number of bytes for the stack.  If the stack
  825. *                            units are INT32Us then, the stack contains '4 * stk_size' bytes.  The stack
  826. *                            units are established by the #define constant OS_STK which is CPU
  827. *                            specific.  'stk_size' is 0 if called by 'OSTaskCreate()'.
  828. *
  829. *              pext          is a pointer to a user supplied memory area that is used to extend the task
  830. *                            control block.  This allows you to store the contents of floating-point
  831. *                            registers, MMU registers or anything else you could find useful during a
  832. *                            context switch.  You can even assign a name to each task and store this name
  833. *                            in this TCB extension.  A NULL pointer is passed if called by OSTaskCreate().
  834. *
  835. *              opt           options as passed to 'OSTaskCreateExt()' or,
  836. *                            0 if called from 'OSTaskCreate()'.
  837. *
  838. * Returns    : OS_NO_ERR         if the call was successful
  839. *              OS_NO_MORE_TCB    if there are no more free TCBs to be allocated and thus, the task cannot
  840. *                                be created.
  841. *
  842. * Note       : This function is INTERNAL to uC/OS-II and your application should not call it.
  843. *********************************************************************************************************
  844. */
  845. INT8U  OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
  846. {
  847. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  848.     OS_CPU_SR  cpu_sr;
  849. #endif    
  850.     OS_TCB    *ptcb;
  851.     OS_ENTER_CRITICAL();
  852.     ptcb = OSTCBFreeList;                                  /* Get a free TCB from the free TCB list    */
  853.     if (ptcb != (OS_TCB *)0) {
  854.         OSTCBFreeList        = ptcb->OSTCBNext;            /* Update pointer to free TCB list          */
  855.         OS_EXIT_CRITICAL();
  856.         ptcb->OSTCBStkPtr    = ptos;                       /* Load Stack pointer in TCB                */
  857.         ptcb->OSTCBPrio      = (INT8U)prio;                /* Load task priority into TCB              */
  858.         ptcb->OSTCBStat      = OS_STAT_RDY;                /* Task is ready to run                     */
  859.         ptcb->OSTCBDly       = 0;                          /* Task is not delayed                      */
  860. #if OS_TASK_CREATE_EXT_EN > 0
  861.         ptcb->OSTCBExtPtr    = pext;                       /* Store pointer to TCB extension           */
  862.         ptcb->OSTCBStkSize   = stk_size;                   /* Store stack size                         */
  863.         ptcb->OSTCBStkBottom = pbos;                       /* Store pointer to bottom of stack         */
  864.         ptcb->OSTCBOpt       = opt;                        /* Store task options                       */
  865.         ptcb->OSTCBId        = id;                         /* Store task ID                            */
  866. #else
  867.         pext                 = pext;                       /* Prevent compiler warning if not used     */
  868.         stk_size             = stk_size;
  869.         pbos                 = pbos;
  870.         opt                  = opt;
  871.         id                   = id;
  872. #endif
  873. #if OS_TASK_DEL_EN > 0
  874.         ptcb->OSTCBDelReq    = OS_NO_ERR;
  875. #endif
  876.         ptcb->OSTCBY         = prio >> 3;                  /* Pre-compute X, Y, BitX and BitY          */
  877.         ptcb->OSTCBBitY      = OSMapTbl[ptcb->OSTCBY];
  878.         ptcb->OSTCBX         = prio & 0x07;
  879.         ptcb->OSTCBBitX      = OSMapTbl[ptcb->OSTCBX];
  880. #if OS_EVENT_EN > 0
  881.         ptcb->OSTCBEventPtr  = (OS_EVENT *)0;              /* Task is not pending on an event          */
  882. #endif
  883. #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
  884.         ptcb->OSTCBFlagNode  = (OS_FLAG_NODE *)0;          /* Task is not pending on an event flag     */
  885. #endif
  886. #if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
  887.         ptcb->OSTCBMsg       = (void *)0;                  /* No message received                      */
  888. #endif
  889. #if OS_VERSION >= 204
  890.         OSTCBInitHook(ptcb);
  891. #endif
  892.         OSTaskCreateHook(ptcb);                            /* Call user defined hook                   */
  893.         
  894.         OS_ENTER_CRITICAL();
  895.         OSTCBPrioTbl[prio] = ptcb;
  896.         ptcb->OSTCBNext    = OSTCBList;                    /* Link into TCB chain                      */
  897.         ptcb->OSTCBPrev    = (OS_TCB *)0;
  898.         if (OSTCBList != (OS_TCB *)0) {
  899.             OSTCBList->OSTCBPrev = ptcb;
  900.         }
  901.         OSTCBList               = ptcb;
  902.         OSRdyGrp               |= ptcb->OSTCBBitY;         /* Make task ready to run                   */
  903.         OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  904.         OS_EXIT_CRITICAL();
  905.         return (OS_NO_ERR);
  906.     }
  907.     OS_EXIT_CRITICAL();
  908.     return (OS_NO_MORE_TCB);
  909. }