PageRenderTime 59ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/compiler/ucos-vs2008/UCOS_SIM/src/ucosii/os_core.c

http://ftk.googlecode.com/
C | 1522 lines | 819 code | 131 blank | 572 comment | 145 complexity | dc9b969887c73e9e3445928058ba2774 MD5 | raw file
Possible License(s): LGPL-3.0
  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 no