/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

Large files are truncated click here to view the full file

  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