os_core.c 84 KB

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