os_task.c 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267
  1. /*
  2. ************************************************************************************************************************
  3. * uC/OS-III
  4. * The Real-Time Kernel
  5. *
  6. * (c) Copyright 2009-2011; Micrium, Inc.; Weston, FL
  7. * All rights reserved. Protected by international copyright laws.
  8. *
  9. * TASK MANAGEMENT
  10. *
  11. * File : OS_TASK.C
  12. * By : JJL
  13. * Version : V3.02.00
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
  18. * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
  19. * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
  20. * application/product. We provide ALL the source code for your convenience and to help you
  21. * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
  22. * it commercially without paying a licensing fee.
  23. *
  24. * Knowledge of the source code may NOT be used to develop a similar product.
  25. *
  26. * Please help us continue to provide the embedded community with the finest software available.
  27. * Your honesty is greatly appreciated.
  28. *
  29. * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
  30. ************************************************************************************************************************
  31. */
  32. #include <os.h>
  33. #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
  34. const CPU_CHAR *os_task__c = "$Id: $";
  35. #endif
  36. /*
  37. ************************************************************************************************************************
  38. * CHANGE PRIORITY OF A TASK
  39. *
  40. * Description: This function allows you to change the priority of a task dynamically. Note that the new
  41. * priority MUST be available.
  42. *
  43. * Arguments : p_tcb is the TCB of the tack to change the priority for
  44. *
  45. * prio_new is the new priority
  46. *
  47. * p_err is a pointer to an error code returned by this function:
  48. *
  49. * OS_ERR_NONE is the call was successful
  50. * OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed
  51. * (i.e. >= (OS_CFG_PRIO_MAX-1))
  52. * OS_ERR_STATE_INVALID if the task is in an invalid state
  53. * OS_ERR_TASK_CHANGE_PRIO_ISR if you tried to change the task's priority from an ISR
  54. ************************************************************************************************************************
  55. */
  56. #if OS_CFG_TASK_CHANGE_PRIO_EN > 0u
  57. void OSTaskChangePrio (OS_TCB *p_tcb,
  58. OS_PRIO prio_new,
  59. OS_ERR *p_err)
  60. {
  61. CPU_BOOLEAN self;
  62. CPU_SR_ALLOC();
  63. #ifdef OS_SAFETY_CRITICAL
  64. if (p_err == (OS_ERR *)0) {
  65. OS_SAFETY_CRITICAL_EXCEPTION();
  66. return;
  67. }
  68. #endif
  69. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  70. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ---------- CANNOT CREATE A TASK FROM AN ISR ---------- */
  71. *p_err = OS_ERR_TASK_CHANGE_PRIO_ISR;
  72. return;
  73. }
  74. #endif
  75. if (prio_new >= (OS_CFG_PRIO_MAX - 1u)) { /* Cannot set to Idle Task priority */
  76. *p_err = OS_ERR_PRIO_INVALID;
  77. return;
  78. }
  79. if (p_tcb == (OS_TCB *)0) { /* See if want to change priority of 'self' */
  80. CPU_CRITICAL_ENTER();
  81. p_tcb = OSTCBCurPtr;
  82. CPU_CRITICAL_EXIT();
  83. self = DEF_TRUE;
  84. } else {
  85. self = DEF_FALSE;
  86. }
  87. OS_CRITICAL_ENTER();
  88. switch (p_tcb->TaskState) {
  89. case OS_TASK_STATE_RDY:
  90. OS_RdyListRemove(p_tcb); /* Remove from current priority */
  91. p_tcb->Prio = prio_new; /* Set new task priority */
  92. OS_PrioInsert(p_tcb->Prio);
  93. if (self == DEF_TRUE) {
  94. OS_RdyListInsertHead(p_tcb);
  95. } else {
  96. OS_RdyListInsertTail(p_tcb);
  97. }
  98. break;
  99. case OS_TASK_STATE_DLY: /* Nothing to do except change the priority in the OS_TCB */
  100. case OS_TASK_STATE_SUSPENDED:
  101. case OS_TASK_STATE_DLY_SUSPENDED:
  102. p_tcb->Prio = prio_new; /* Set new task priority */
  103. break;
  104. case OS_TASK_STATE_PEND:
  105. case OS_TASK_STATE_PEND_TIMEOUT:
  106. case OS_TASK_STATE_PEND_SUSPENDED:
  107. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  108. switch (p_tcb->PendOn) { /* What to do depends on what we are pending on */
  109. case OS_TASK_PEND_ON_TASK_Q: /* Nothing to do except change the priority in the OS_TCB */
  110. case OS_TASK_PEND_ON_TASK_SEM:
  111. case OS_TASK_PEND_ON_FLAG:
  112. p_tcb->Prio = prio_new; /* Set new task priority */
  113. break;
  114. case OS_TASK_PEND_ON_MUTEX:
  115. case OS_TASK_PEND_ON_MULTI:
  116. case OS_TASK_PEND_ON_Q:
  117. case OS_TASK_PEND_ON_SEM:
  118. OS_PendListChangePrio(p_tcb,
  119. prio_new);
  120. break;
  121. default:
  122. break;
  123. }
  124. break;
  125. default:
  126. OS_CRITICAL_EXIT();
  127. *p_err = OS_ERR_STATE_INVALID;
  128. return;
  129. }
  130. OS_CRITICAL_EXIT_NO_SCHED();
  131. OSSched(); /* Run highest priority task ready */
  132. *p_err = OS_ERR_NONE;
  133. }
  134. #endif
  135. /*$PAGE*/
  136. /*
  137. ************************************************************************************************************************
  138. * CREATE A TASK
  139. *
  140. * Description: This function is used to have uC/OS-III manage the execution of a task. Tasks can either be created
  141. * prior to the start of multitasking or by a running task. A task cannot be created by an ISR.
  142. *
  143. * Arguments : p_tcb is a pointer to the task's TCB
  144. *
  145. * p_name is a pointer to an ASCII string to provide a name to the task.
  146. *
  147. * p_task is a pointer to the task's code
  148. *
  149. * p_arg is a pointer to an optional data area which can be used to pass parameters to
  150. * the task when the task first executes. Where the task is concerned it thinks
  151. * it was invoked and passed the argument 'p_arg' as follows:
  152. *
  153. * void Task (void *p_arg)
  154. * {
  155. * for (;;) {
  156. * Task code;
  157. * }
  158. * }
  159. *
  160. * prio is the task's priority. A unique priority MUST be assigned to each task and the
  161. * lower the number, the higher the priority.
  162. *
  163. * p_stk_base is a pointer to the base address of the stack (i.e. low address).
  164. *
  165. * stk_limit is the number of stack elements to set as 'watermark' limit for the stack. This value
  166. * represents the number of CPU_STK entries left before the stack is full. For example,
  167. * specifying 10% of the 'stk_size' value indicates that the stack limit will be reached
  168. * when the stack reaches 90% full.
  169. *
  170. * stk_size is the size of the stack in number of elements. If CPU_STK is set to CPU_INT08U,
  171. * 'stk_size' corresponds to the number of bytes available. If CPU_STK is set to
  172. * CPU_INT16U, 'stk_size' contains the number of 16-bit entries available. Finally, if
  173. * CPU_STK is set to CPU_INT32U, 'stk_size' contains the number of 32-bit entries
  174. * available on the stack.
  175. *
  176. * q_size is the maximum number of messages that can be sent to the task
  177. *
  178. * time_quanta amount of time (in ticks) for time slice when round-robin between tasks. Specify 0 to use
  179. * the default.
  180. *
  181. * p_ext is a pointer to a user supplied memory location which is used as a TCB extension.
  182. * For example, this user memory can hold the contents of floating-point registers
  183. * during a context switch, the time each task takes to execute, the number of times
  184. * the task has been switched-in, etc.
  185. *
  186. * opt contains additional information (or options) about the behavior of the task.
  187. * See OS_OPT_TASK_xxx in OS.H. Current choices are:
  188. *
  189. * OS_OPT_TASK_NONE No option selected
  190. * OS_OPT_TASK_STK_CHK Stack checking to be allowed for the task
  191. * OS_OPT_TASK_STK_CLR Clear the stack when the task is created
  192. * OS_OPT_TASK_SAVE_FP If the CPU has floating-point registers, save them
  193. * during a context switch.
  194. *
  195. * p_err is a pointer to an error code that will be set during this call. The value pointer
  196. * to by 'p_err' can be:
  197. *
  198. * OS_ERR_NONE if the function was successful.
  199. * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the task after you called
  200. * OSSafetyCriticalStart().
  201. * OS_ERR_NAME if 'p_name' is a NULL pointer
  202. * OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum
  203. * allowed (i.e. >= OS_CFG_PRIO_MAX-1) or,
  204. * if OS_CFG_ISR_POST_DEFERRED_EN is set to 1 and you tried
  205. * to use priority 0 which is reserved.
  206. * OS_ERR_STK_INVALID if you specified a NULL pointer for 'p_stk_base'
  207. * OS_ERR_STK_SIZE_INVALID if you specified zero for the 'stk_size'
  208. * OS_ERR_STK_LIMIT_INVALID if you specified a 'stk_limit' greater than or equal
  209. * to 'stk_size'
  210. * OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR.
  211. * OS_ERR_TASK_INVALID if you specified a NULL pointer for 'p_task'
  212. * OS_ERR_TCB_INVALID if you specified a NULL pointer for 'p_tcb'
  213. *
  214. * Returns : A pointer to the TCB of the task created. This pointer must be used as an ID (i.e handle) to the task.
  215. ************************************************************************************************************************
  216. */
  217. /*$PAGE*/
  218. void OSTaskCreate (OS_TCB *p_tcb,
  219. CPU_CHAR *p_name,
  220. OS_TASK_PTR p_task,
  221. void *p_arg,
  222. OS_PRIO prio,
  223. CPU_STK *p_stk_base,
  224. CPU_STK_SIZE stk_limit,
  225. CPU_STK_SIZE stk_size,
  226. OS_MSG_QTY q_size,
  227. OS_TICK time_quanta,
  228. void *p_ext,
  229. OS_OPT opt,
  230. OS_ERR *p_err)
  231. {
  232. CPU_STK_SIZE i;
  233. #if OS_CFG_TASK_REG_TBL_SIZE > 0u
  234. OS_OBJ_QTY reg_nbr;
  235. #endif
  236. CPU_STK *p_sp;
  237. CPU_STK *p_stk_limit;
  238. CPU_SR_ALLOC();
  239. #ifdef OS_SAFETY_CRITICAL
  240. if (p_err == (OS_ERR *)0) {
  241. OS_SAFETY_CRITICAL_EXCEPTION();
  242. return;
  243. }
  244. #endif
  245. #ifdef OS_SAFETY_CRITICAL_IEC61508
  246. if (OSSafetyCriticalStartFlag == DEF_TRUE) {
  247. *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  248. return;
  249. }
  250. #endif
  251. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  252. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ---------- CANNOT CREATE A TASK FROM AN ISR ---------- */
  253. *p_err = OS_ERR_TASK_CREATE_ISR;
  254. return;
  255. }
  256. #endif
  257. #if OS_CFG_ARG_CHK_EN > 0u /* ---------------- VALIDATE ARGUMENTS ------------------ */
  258. if (p_tcb == (OS_TCB *)0) { /* User must supply a valid OS_TCB */
  259. *p_err = OS_ERR_TCB_INVALID;
  260. return;
  261. }
  262. if (p_task == (OS_TASK_PTR)0) { /* User must supply a valid task */
  263. *p_err = OS_ERR_TASK_INVALID;
  264. return;
  265. }
  266. if (p_stk_base == (CPU_STK *)0) { /* User must supply a valid stack base address */
  267. *p_err = OS_ERR_STK_INVALID;
  268. return;
  269. }
  270. if (stk_size < OSCfg_StkSizeMin) { /* User must supply a valid minimum stack size */
  271. *p_err = OS_ERR_STK_SIZE_INVALID;
  272. return;
  273. }
  274. if (stk_limit >= stk_size) { /* User must supply a valid stack limit */
  275. *p_err = OS_ERR_STK_LIMIT_INVALID;
  276. return;
  277. }
  278. if (prio >= OS_CFG_PRIO_MAX) { /* Priority must be within 0 and OS_CFG_PRIO_MAX-1 */
  279. *p_err = OS_ERR_PRIO_INVALID;
  280. return;
  281. }
  282. #endif
  283. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  284. if (prio == (OS_PRIO)0) {
  285. if (p_tcb != &OSIntQTaskTCB) {
  286. *p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use priority 0 */
  287. return;
  288. }
  289. }
  290. #endif
  291. if (prio == (OS_CFG_PRIO_MAX - 1u)) {
  292. if (p_tcb != &OSIdleTaskTCB) {
  293. *p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use same priority as idle task */
  294. return;
  295. }
  296. }
  297. OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */
  298. *p_err = OS_ERR_NONE;
  299. /* --------------- CLEAR THE TASK'S STACK --------------- */
  300. if ((opt & OS_OPT_TASK_STK_CHK) != (OS_OPT)0) { /* See if stack checking has been enabled */
  301. if ((opt & OS_OPT_TASK_STK_CLR) != (OS_OPT)0) { /* See if stack needs to be cleared */
  302. p_sp = p_stk_base;
  303. for (i = 0u; i < stk_size; i++) { /* Stack grows from HIGH to LOW memory */
  304. *p_sp = (CPU_STK)0; /* Clear from bottom of stack and up! */
  305. p_sp++;
  306. }
  307. }
  308. }
  309. /* ------- INITIALIZE THE STACK FRAME OF THE TASK ------- */
  310. #if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO)
  311. p_stk_limit = p_stk_base + stk_limit;
  312. #else
  313. p_stk_limit = p_stk_base + (stk_size - 1u) - stk_limit;
  314. #endif
  315. p_sp = OSTaskStkInit(p_task,
  316. p_arg,
  317. p_stk_base,
  318. p_stk_limit,
  319. stk_size,
  320. opt);
  321. /* -------------- INITIALIZE THE TCB FIELDS ------------- */
  322. p_tcb->TaskEntryAddr = p_task; /* Save task entry point address */
  323. p_tcb->TaskEntryArg = p_arg; /* Save task entry argument */
  324. p_tcb->NamePtr = p_name; /* Save task name */
  325. p_tcb->Prio = prio; /* Save the task's priority */
  326. p_tcb->StkPtr = p_sp; /* Save the new top-of-stack pointer */
  327. p_tcb->StkLimitPtr = p_stk_limit; /* Save the stack limit pointer */
  328. p_tcb->TimeQuanta = time_quanta; /* Save the #ticks for time slice (0 means not sliced) */
  329. #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
  330. if (time_quanta == (OS_TICK)0) {
  331. p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
  332. } else {
  333. p_tcb->TimeQuantaCtr = time_quanta;
  334. }
  335. #endif
  336. p_tcb->ExtPtr = p_ext; /* Save pointer to TCB extension */
  337. p_tcb->StkBasePtr = p_stk_base; /* Save pointer to the base address of the stack */
  338. p_tcb->StkSize = stk_size; /* Save the stack size (in number of CPU_STK elements) */
  339. p_tcb->Opt = opt; /* Save task options */
  340. #if OS_CFG_TASK_REG_TBL_SIZE > 0u
  341. for (reg_nbr = 0u; reg_nbr < OS_CFG_TASK_REG_TBL_SIZE; reg_nbr++) {
  342. p_tcb->RegTbl[reg_nbr] = (OS_REG)0;
  343. }
  344. #endif
  345. #if OS_CFG_TASK_Q_EN > 0u
  346. OS_MsgQInit(&p_tcb->MsgQ, /* Initialize the task's message queue */
  347. q_size);
  348. #endif
  349. OSTaskCreateHook(p_tcb); /* Call user defined hook */
  350. /* --------------- ADD TASK TO READY LIST --------------- */
  351. OS_CRITICAL_ENTER();
  352. OS_PrioInsert(p_tcb->Prio);
  353. OS_RdyListInsertTail(p_tcb);
  354. #if OS_CFG_DBG_EN > 0u
  355. OS_TaskDbgListAdd(p_tcb);
  356. #endif
  357. OSTaskQty++; /* Increment the #tasks counter */
  358. if (OSRunning != OS_STATE_OS_RUNNING) { /* Return if multitasking has not started */
  359. OS_CRITICAL_EXIT();
  360. return;
  361. }
  362. OS_CRITICAL_EXIT_NO_SCHED();
  363. OSSched();
  364. }
  365. /*$PAGE*/
  366. /*
  367. ************************************************************************************************************************
  368. * DELETE A TASK
  369. *
  370. * Description: This function allows you to delete a task. The calling task can delete itself by specifying a NULL
  371. * pointer for 'p_tcb'. The deleted task is returned to the dormant state and can be re-activated by
  372. * creating the deleted task again.
  373. *
  374. * Arguments : p_tcb is the TCB of the tack to delete
  375. *
  376. * p_err is a pointer to an error code returned by this function:
  377. *
  378. * OS_ERR_NONE if the call is successful
  379. * OS_ERR_STATE_INVALID if the state of the task is invalid
  380. * OS_ERR_TASK_DEL_IDLE if you attempted to delete uC/OS-III's idle task
  381. * OS_ERR_TASK_DEL_INVALID if you attempted to delete uC/OS-III's ISR handler task
  382. * OS_ERR_TASK_DEL_ISR if you tried to delete a task from an ISR
  383. ************************************************************************************************************************
  384. */
  385. #if OS_CFG_TASK_DEL_EN > 0u
  386. void OSTaskDel (OS_TCB *p_tcb,
  387. OS_ERR *p_err)
  388. {
  389. CPU_SR_ALLOC();
  390. #ifdef OS_SAFETY_CRITICAL
  391. if (p_err == (OS_ERR *)0) {
  392. OS_SAFETY_CRITICAL_EXCEPTION();
  393. return;
  394. }
  395. #endif
  396. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  397. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to delete from ISR */
  398. *p_err = OS_ERR_TASK_DEL_ISR;
  399. return;
  400. }
  401. #endif
  402. if (p_tcb == &OSIdleTaskTCB) { /* Not allowed to delete the idle task */
  403. *p_err = OS_ERR_TASK_DEL_IDLE;
  404. return;
  405. }
  406. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  407. if (p_tcb == &OSIntQTaskTCB) { /* Cannot delete the ISR handler task */
  408. *p_err = OS_ERR_TASK_DEL_INVALID;
  409. return;
  410. }
  411. #endif
  412. if (p_tcb == (OS_TCB *)0) { /* Delete 'Self'? */
  413. CPU_CRITICAL_ENTER();
  414. p_tcb = OSTCBCurPtr; /* Yes. */
  415. CPU_CRITICAL_EXIT();
  416. }
  417. OS_CRITICAL_ENTER();
  418. switch (p_tcb->TaskState) {
  419. case OS_TASK_STATE_RDY:
  420. OS_RdyListRemove(p_tcb);
  421. break;
  422. case OS_TASK_STATE_SUSPENDED:
  423. break;
  424. case OS_TASK_STATE_DLY: /* Task is only delayed, not on any wait list */
  425. case OS_TASK_STATE_DLY_SUSPENDED:
  426. OS_TickListRemove(p_tcb);
  427. break;
  428. case OS_TASK_STATE_PEND:
  429. case OS_TASK_STATE_PEND_SUSPENDED:
  430. case OS_TASK_STATE_PEND_TIMEOUT:
  431. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  432. OS_TickListRemove(p_tcb);
  433. switch (p_tcb->PendOn) { /* See what we are pending on */
  434. case OS_TASK_PEND_ON_NOTHING:
  435. case OS_TASK_PEND_ON_TASK_Q: /* There is no wait list for these two */
  436. case OS_TASK_PEND_ON_TASK_SEM:
  437. break;
  438. case OS_TASK_PEND_ON_FLAG: /* Remove from wait list */
  439. case OS_TASK_PEND_ON_MULTI:
  440. case OS_TASK_PEND_ON_MUTEX:
  441. case OS_TASK_PEND_ON_Q:
  442. case OS_TASK_PEND_ON_SEM:
  443. OS_PendListRemove(p_tcb);
  444. break;
  445. default:
  446. break;
  447. }
  448. break;
  449. default:
  450. OS_CRITICAL_EXIT();
  451. *p_err = OS_ERR_STATE_INVALID;
  452. return;
  453. }
  454. #if OS_CFG_TASK_Q_EN > 0u
  455. (void)OS_MsgQFreeAll(&p_tcb->MsgQ); /* Free task's message queue messages */
  456. #endif
  457. OSTaskDelHook(p_tcb); /* Call user defined hook */
  458. #if OS_CFG_DBG_EN > 0u
  459. OS_TaskDbgListRemove(p_tcb);
  460. #endif
  461. OSTaskQty--; /* One less task being managed */
  462. OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */
  463. p_tcb->TaskState = (OS_STATE)OS_TASK_STATE_DEL; /* Indicate that the task was deleted */
  464. OS_CRITICAL_EXIT_NO_SCHED();
  465. OSSched(); /* Find new highest priority task */
  466. *p_err = OS_ERR_NONE;
  467. }
  468. #endif
  469. /*$PAGE*/
  470. /*
  471. ************************************************************************************************************************
  472. * FLUSH TASK's QUEUE
  473. *
  474. * Description: This function is used to flush the task's internal message queue.
  475. *
  476. * Arguments : p_tcb is a pointer to the task's OS_TCB. Specifying a NULL pointer indicates that you wish to
  477. * flush the message queue of the calling task.
  478. *
  479. * p_err is a pointer to a variable that will contain an error code returned by this function.
  480. *
  481. * OS_ERR_NONE upon success
  482. * OS_ERR_FLUSH_ISR if you called this function from an ISR
  483. *
  484. * Returns : The number of entries freed from the queue
  485. *
  486. * Note(s) : 1) You should use this function with great care because, when to flush the queue, you LOOSE the
  487. * references to what the queue entries are pointing to and thus, you could cause 'memory leaks'. In
  488. * other words, the data you are pointing to that's being referenced by the queue entries should, most
  489. * likely, need to be de-allocated (i.e. freed).
  490. ************************************************************************************************************************
  491. */
  492. #if OS_CFG_TASK_Q_EN > 0u
  493. OS_MSG_QTY OSTaskQFlush (OS_TCB *p_tcb,
  494. OS_ERR *p_err)
  495. {
  496. OS_MSG_QTY entries;
  497. CPU_SR_ALLOC();
  498. #ifdef OS_SAFETY_CRITICAL
  499. if (p_err == (OS_ERR *)0) {
  500. OS_SAFETY_CRITICAL_EXCEPTION();
  501. return ((OS_MSG_QTY)0);
  502. }
  503. #endif
  504. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  505. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't flush a message queue from an ISR */
  506. *p_err = OS_ERR_FLUSH_ISR;
  507. return ((OS_MSG_QTY)0);
  508. }
  509. #endif
  510. if (p_tcb == (OS_TCB *)0) { /* Flush message queue of calling task? */
  511. CPU_CRITICAL_ENTER();
  512. p_tcb = OSTCBCurPtr;
  513. CPU_CRITICAL_EXIT();
  514. }
  515. OS_CRITICAL_ENTER();
  516. entries = OS_MsgQFreeAll(&p_tcb->MsgQ); /* Return all OS_MSGs to the OS_MSG pool */
  517. OS_CRITICAL_EXIT();
  518. *p_err = OS_ERR_NONE;
  519. return (entries);
  520. }
  521. #endif
  522. /*$PAGE*/
  523. /*
  524. ************************************************************************************************************************
  525. * WAIT FOR A MESSAGE
  526. *
  527. * Description: This function causes the current task to wait for a message to be posted to it.
  528. *
  529. * Arguments : timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a
  530. * message to arrive up to the amount of time specified by this argument.
  531. * If you specify 0, however, your task will wait forever or, until a message arrives.
  532. *
  533. * opt determines whether the user wants to block if the task's queue is empty or not:
  534. *
  535. * OS_OPT_PEND_BLOCKING
  536. * OS_OPT_PEND_NON_BLOCKING
  537. *
  538. * p_msg_size is a pointer to a variable that will receive the size of the message
  539. *
  540. * p_ts is a pointer to a variable that will receive the timestamp of when the message was
  541. * received. If you pass a NULL pointer (i.e. (CPU_TS *)0) then you will not get the
  542. * timestamp. In other words, passing a NULL pointer is valid and indicates that you don't
  543. * need the timestamp.
  544. *
  545. * p_err is a pointer to where an error message will be deposited. Possible error
  546. * messages are:
  547. *
  548. * OS_ERR_NONE The call was successful and your task received a message.
  549. * OS_ERR_PEND_ABORT
  550. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  551. * OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the queue was not empty
  552. * OS_ERR_Q_EMPTY
  553. * OS_ERR_SCHED_LOCKED If the scheduler is locked
  554. * OS_ERR_TIMEOUT A message was not received within the specified timeout
  555. * would lead to a suspension.
  556. *
  557. * Returns : A pointer to the message received or a NULL pointer upon error.
  558. *
  559. * Note(s) : 1) It is possible to receive NULL pointers when there are no errors.
  560. ************************************************************************************************************************
  561. */
  562. #if OS_CFG_TASK_Q_EN > 0u
  563. void *OSTaskQPend (OS_TICK timeout,
  564. OS_OPT opt,
  565. OS_MSG_SIZE *p_msg_size,
  566. CPU_TS *p_ts,
  567. OS_ERR *p_err)
  568. {
  569. OS_MSG_Q *p_msg_q;
  570. void *p_void;
  571. CPU_SR_ALLOC();
  572. #ifdef OS_SAFETY_CRITICAL
  573. if (p_err == (OS_ERR *)0) {
  574. OS_SAFETY_CRITICAL_EXCEPTION();
  575. return ((void *)0);
  576. }
  577. #endif
  578. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  579. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't Pend from an ISR */
  580. *p_err = OS_ERR_PEND_ISR;
  581. return ((void *)0);
  582. }
  583. #endif
  584. #if OS_CFG_ARG_CHK_EN > 0u /* ---------------- VALIDATE ARGUMENTS ------------------ */
  585. if (p_msg_size == (OS_MSG_SIZE *)0) { /* User must supply a valid destination for msg size */
  586. *p_err = OS_ERR_PTR_INVALID;
  587. return ((void *)0);
  588. }
  589. switch (opt) { /* User must supply a valid option */
  590. case OS_OPT_PEND_BLOCKING:
  591. case OS_OPT_PEND_NON_BLOCKING:
  592. break;
  593. default:
  594. *p_err = OS_ERR_OPT_INVALID;
  595. return ((void *)0);
  596. }
  597. #endif
  598. if (p_ts != (CPU_TS *)0) {
  599. *p_ts = (CPU_TS )0; /* Initialize the returned timestamp */
  600. }
  601. CPU_CRITICAL_ENTER();
  602. p_msg_q = &OSTCBCurPtr->MsgQ; /* Any message waiting in the message queue? */
  603. p_void = OS_MsgQGet(p_msg_q,
  604. p_msg_size,
  605. p_ts,
  606. p_err);
  607. if (*p_err == OS_ERR_NONE) {
  608. #if OS_CFG_TASK_PROFILE_EN > 0u
  609. if (p_ts != (CPU_TS *)0) {
  610. OSTCBCurPtr->MsgQPendTime = OS_TS_GET() - *p_ts;
  611. if (OSTCBCurPtr->MsgQPendTime > OSTCBCurPtr->MsgQPendTimeMax) {
  612. OSTCBCurPtr->MsgQPendTimeMax = OSTCBCurPtr->MsgQPendTime;
  613. }
  614. }
  615. #endif
  616. CPU_CRITICAL_EXIT();
  617. return (p_void); /* Yes, Return oldest message received */
  618. }
  619. if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */
  620. *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */
  621. CPU_CRITICAL_EXIT();
  622. return ((void *)0);
  623. } else { /* Yes */
  624. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't block when the scheduler is locked */
  625. CPU_CRITICAL_EXIT();
  626. *p_err = OS_ERR_SCHED_LOCKED;
  627. return ((void *)0);
  628. }
  629. }
  630. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
  631. OS_Pend((OS_PEND_DATA *)0, /* Block task pending on Message */
  632. (OS_PEND_OBJ *)0,
  633. (OS_STATE )OS_TASK_PEND_ON_TASK_Q,
  634. (OS_TICK )timeout);
  635. OS_CRITICAL_EXIT_NO_SCHED();
  636. OSSched(); /* Find the next highest priority task ready to run */
  637. CPU_CRITICAL_ENTER();
  638. switch (OSTCBCurPtr->PendStatus) {
  639. case OS_STATUS_PEND_OK: /* Extract message from TCB (Put there by Post) */
  640. p_void = OSTCBCurPtr->MsgPtr;
  641. *p_msg_size = OSTCBCurPtr->MsgSize;
  642. if (p_ts != (CPU_TS *)0) {
  643. *p_ts = OSTCBCurPtr->TS;
  644. #if OS_CFG_TASK_PROFILE_EN > 0u
  645. OSTCBCurPtr->MsgQPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
  646. if (OSTCBCurPtr->MsgQPendTime > OSTCBCurPtr->MsgQPendTimeMax) {
  647. OSTCBCurPtr->MsgQPendTimeMax = OSTCBCurPtr->MsgQPendTime;
  648. }
  649. #endif
  650. }
  651. *p_err = OS_ERR_NONE;
  652. break;
  653. case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */
  654. p_void = (void *)0;
  655. *p_msg_size = (OS_MSG_SIZE)0;
  656. if (p_ts != (CPU_TS *)0) {
  657. *p_ts = (CPU_TS )0;
  658. }
  659. *p_err = OS_ERR_PEND_ABORT;
  660. break;
  661. case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get event within TO */
  662. default:
  663. p_void = (void *)0;
  664. *p_msg_size = (OS_MSG_SIZE)0;
  665. if (p_ts != (CPU_TS *)0) {
  666. *p_ts = OSTCBCurPtr->TS;
  667. }
  668. *p_err = OS_ERR_TIMEOUT;
  669. break;
  670. }
  671. CPU_CRITICAL_EXIT();
  672. return (p_void); /* Return received message */
  673. }
  674. #endif
  675. /*$PAGE*/
  676. /*
  677. ************************************************************************************************************************
  678. * ABORT WAITING FOR A MESSAGE
  679. *
  680. * Description: This function aborts & readies the task specified. This function should be used to fault-abort the wait
  681. * for a message, rather than to normally post the message to the task via OSTaskQPost().
  682. *
  683. * Arguments : p_tcb is a pointer to the task to pend abort
  684. *
  685. * opt provides options for this function:
  686. *
  687. * OS_OPT_POST_NONE No option specified
  688. * OS_OPT_POST_NO_SCHED Indicates that the scheduler will not be called.
  689. *
  690. * p_err is a pointer to a variable that will contain an error code returned by this function.
  691. *
  692. * OS_ERR_NONE If the task was readied and informed of the aborted wait
  693. * OS_ERR_PEND_ABORT_ISR If you called this function from an ISR
  694. * OS_ERR_PEND_ABORT_NONE If task was not pending on a message and thus there is nothing to
  695. * abort.
  696. * OS_ERR_PEND_ABORT_SELF If you passed a NULL pointer for 'p_tcb'
  697. *
  698. * Returns : == DEF_FALSE if task was not waiting for a message, or upon error.
  699. * == DEF_TRUE if task was waiting for a message and was readied and informed.
  700. ************************************************************************************************************************
  701. */
  702. #if (OS_CFG_TASK_Q_EN > 0u) && (OS_CFG_TASK_Q_PEND_ABORT_EN > 0u)
  703. CPU_BOOLEAN OSTaskQPendAbort (OS_TCB *p_tcb,
  704. OS_OPT opt,
  705. OS_ERR *p_err)
  706. {
  707. CPU_TS ts;
  708. CPU_SR_ALLOC();
  709. #ifdef OS_SAFETY_CRITICAL
  710. if (p_err == (OS_ERR *)0) {
  711. OS_SAFETY_CRITICAL_EXCEPTION();
  712. return (DEF_FALSE);
  713. }
  714. #endif
  715. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  716. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from ISR ... */
  717. *p_err = OS_ERR_PEND_ABORT_ISR; /* ... can't Pend Abort from an ISR */
  718. return (DEF_FALSE);
  719. }
  720. #endif
  721. CPU_CRITICAL_ENTER();
  722. #if OS_CFG_ARG_CHK_EN > 0u
  723. if ((p_tcb == (OS_TCB *)0) || /* Pend abort self? */
  724. (p_tcb == OSTCBCurPtr)) {
  725. CPU_CRITICAL_EXIT();
  726. *p_err = OS_ERR_PEND_ABORT_SELF; /* ... doesn't make sense */
  727. return (DEF_FALSE);
  728. }
  729. #endif
  730. if (p_tcb->PendOn != OS_TASK_PEND_ON_TASK_Q) { /* Is task waiting for a message? */
  731. CPU_CRITICAL_EXIT(); /* No */
  732. *p_err = OS_ERR_PEND_ABORT_NONE;
  733. return (DEF_FALSE);
  734. }
  735. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  736. ts = OS_TS_GET(); /* Get timestamp of when the abort occurred */
  737. OS_PendAbort((OS_PEND_OBJ *)0, /* Abort the pend */
  738. p_tcb,
  739. ts);
  740. OS_CRITICAL_EXIT_NO_SCHED();
  741. if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
  742. OSSched(); /* Run the scheduler */
  743. }
  744. *p_err = OS_ERR_NONE;
  745. return (DEF_TRUE);
  746. }
  747. #endif
  748. /*$PAGE*/
  749. /*
  750. ************************************************************************************************************************
  751. * POST MESSAGE TO A TASK
  752. *
  753. * Description: This function sends a message to a task
  754. *
  755. * Arguments : p_tcb is a pointer to the TCB of the task receiving a message. If you specify a NULL pointer then
  756. * the message will be posted to the task's queue of the calling task. In other words, you'd be
  757. * posting a message to yourself.
  758. *
  759. * p_void is a pointer to the message to send.
  760. *
  761. * msg_size is the size of the message sent (in #bytes)
  762. *
  763. * opt specifies whether the post will be FIFO or LIFO:
  764. *
  765. * OS_OPT_POST_FIFO Post at the end of the queue
  766. * OS_OPT_POST_LIFO Post at the front of the queue
  767. *
  768. * OS_OPT_POST_NO_SCHED Do not run the scheduler after the post
  769. *
  770. * Note(s): 1) OS_OPT_POST_NO_SCHED can be added with one of the other options.
  771. *
  772. *
  773. * p_err is a pointer to a variable that will hold the error code associated
  774. * with the outcome of this call. Errors can be:
  775. *
  776. * OS_ERR_NONE The call was successful and the message was sent
  777. * OS_ERR_Q_MAX If the queue is full
  778. * OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs available from the pool
  779. *
  780. * Returns : none
  781. ************************************************************************************************************************
  782. */
  783. #if OS_CFG_TASK_Q_EN > 0u
  784. void OSTaskQPost (OS_TCB *p_tcb,
  785. void *p_void,
  786. OS_MSG_SIZE msg_size,
  787. OS_OPT opt,
  788. OS_ERR *p_err)
  789. {
  790. CPU_TS ts;
  791. #ifdef OS_SAFETY_CRITICAL
  792. if (p_err == (OS_ERR *)0) {
  793. OS_SAFETY_CRITICAL_EXCEPTION();
  794. return;
  795. }
  796. #endif
  797. ts = OS_TS_GET(); /* Get timestamp */
  798. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  799. if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
  800. OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_MSG, /* Post to ISR queue */
  801. (void *)p_tcb,
  802. (void *)p_void,
  803. (OS_MSG_SIZE)msg_size,
  804. (OS_FLAGS )0,
  805. (OS_OPT )opt,
  806. (CPU_TS )ts,
  807. (OS_ERR *)p_err);
  808. return;
  809. }
  810. #endif
  811. OS_TaskQPost(p_tcb,
  812. p_void,
  813. msg_size,
  814. opt,
  815. ts,
  816. p_err);
  817. }
  818. #endif
  819. /*$PAGE*/
  820. /*
  821. ************************************************************************************************************************
  822. * GET THE CURRENT VALUE OF A TASK REGISTER
  823. *
  824. * Description: This function is called to obtain the current value of a task register. Task registers are application
  825. * specific and can be used to store task specific values such as 'error numbers' (i.e. errno), statistics,
  826. * etc.
  827. *
  828. * Arguments : p_tcb is a pointer to the OS_TCB of the task you want to read the register from. If 'p_tcb' is a
  829. * NULL pointer then you will get the register of the current task.
  830. *
  831. * id is the 'id' of the desired task variable. Note that the 'id' must be less than
  832. * OS_CFG_TASK_REG_TBL_SIZE
  833. *
  834. * p_err is a pointer to a variable that will hold an error code related to this call.
  835. *
  836. * OS_ERR_NONE if the call was successful
  837. * OS_ERR_REG_ID_INVALID if the 'id' is not between 0 and OS_CFG_TASK_REG_TBL_SIZE-1
  838. *
  839. * Returns : The current value of the task's register or 0 if an error is detected.
  840. ************************************************************************************************************************
  841. */
  842. #if OS_CFG_TASK_REG_TBL_SIZE > 0u
  843. OS_REG OSTaskRegGet (OS_TCB *p_tcb,
  844. OS_REG_ID id,
  845. OS_ERR *p_err)
  846. {
  847. OS_REG value;
  848. CPU_SR_ALLOC();
  849. #ifdef OS_SAFETY_CRITICAL
  850. if (p_err == (OS_ERR *)0) {
  851. OS_SAFETY_CRITICAL_EXCEPTION();
  852. return ((OS_REG)0);
  853. }
  854. #endif
  855. #if OS_CFG_ARG_CHK_EN > 0u
  856. if (id >= OS_CFG_TASK_REG_TBL_SIZE) {
  857. *p_err = OS_ERR_REG_ID_INVALID;
  858. return ((OS_REG)0);
  859. }
  860. #endif
  861. CPU_CRITICAL_ENTER();
  862. if (p_tcb == (OS_TCB *)0) {
  863. p_tcb = OSTCBCurPtr;
  864. }
  865. value = p_tcb->RegTbl[id];
  866. CPU_CRITICAL_EXIT();
  867. *p_err = OS_ERR_NONE;
  868. return ((OS_REG)value);
  869. }
  870. #endif
  871. /*$PAGE*/
  872. /*
  873. ************************************************************************************************************************
  874. * SET THE CURRENT VALUE OF A TASK REGISTER
  875. *
  876. * Description: This function is called to change the current value of a task register. Task registers are application
  877. * specific and can be used to store task specific values such as 'error numbers' (i.e. errno), statistics,
  878. * etc.
  879. *
  880. * Arguments : p_tcb is a pointer to the OS_TCB of the task you want to set the register for. If 'p_tcb' is a NULL
  881. * pointer then you will change the register of the current task.
  882. *
  883. * id is the 'id' of the desired task register. Note that the 'id' must be less than
  884. * OS_CFG_TASK_REG_TBL_SIZE
  885. *
  886. * value is the desired value for the task register.
  887. *
  888. * p_err is a pointer to a variable that will hold an error code related to this call.
  889. *
  890. * OS_ERR_NONE if the call was successful
  891. * OS_ERR_REG_ID_INVALID if the 'id' is not between 0 and OS_CFG_TASK_REG_TBL_SIZE-1
  892. *
  893. * Returns : none
  894. ************************************************************************************************************************
  895. */
  896. #if OS_CFG_TASK_REG_TBL_SIZE > 0u
  897. void OSTaskRegSet (OS_TCB *p_tcb,
  898. OS_REG_ID id,
  899. OS_REG value,
  900. OS_ERR *p_err)
  901. {
  902. CPU_SR_ALLOC();
  903. #ifdef OS_SAFETY_CRITICAL
  904. if (p_err == (OS_ERR *)0) {
  905. OS_SAFETY_CRITICAL_EXCEPTION();
  906. return;
  907. }
  908. #endif
  909. #if OS_CFG_ARG_CHK_EN > 0u
  910. if (id >= OS_CFG_TASK_REG_TBL_SIZE) {
  911. *p_err = OS_ERR_REG_ID_INVALID;
  912. return;
  913. }
  914. #endif
  915. CPU_CRITICAL_ENTER();
  916. if (p_tcb == (OS_TCB *)0) {
  917. p_tcb = OSTCBCurPtr;
  918. }
  919. p_tcb->RegTbl[id] = value;
  920. CPU_CRITICAL_EXIT();
  921. *p_err = OS_ERR_NONE;
  922. }
  923. #endif
  924. /*$PAGE*/
  925. /*
  926. ************************************************************************************************************************
  927. * RESUME A SUSPENDED TASK
  928. *
  929. * Description: This function is called to resume a previously suspended task. This is the only call that will remove an
  930. * explicit task suspension.
  931. *
  932. * Arguments : p_tcb Is a pointer to the task's OS_TCB to resume
  933. *
  934. * p_err Is a pointer to a variable that will contain an error code returned by this function
  935. *
  936. * OS_ERR_NONE if the requested task is resumed
  937. * OS_ERR_STATE_INVALID if the task is in an invalid state
  938. * OS_ERR_TASK_RESUME_ISR if you called this function from an ISR
  939. * OS_ERR_TASK_RESUME_SELF You cannot resume 'self'
  940. * OS_ERR_TASK_NOT_SUSPENDED if the task to resume has not been suspended
  941. *
  942. * Returns : none
  943. ************************************************************************************************************************
  944. */
  945. #if OS_CFG_TASK_SUSPEND_EN > 0u
  946. void OSTaskResume (OS_TCB *p_tcb,
  947. OS_ERR *p_err)
  948. {
  949. CPU_SR_ALLOC();
  950. #ifdef OS_SAFETY_CRITICAL
  951. if (p_err == (OS_ERR *)0) {
  952. OS_SAFETY_CRITICAL_EXCEPTION();
  953. return;
  954. }
  955. #endif
  956. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  957. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
  958. *p_err = OS_ERR_TASK_RESUME_ISR;
  959. return;
  960. }
  961. #endif
  962. CPU_CRITICAL_ENTER();
  963. #if OS_CFG_ARG_CHK_EN > 0u
  964. if ((p_tcb == (OS_TCB *)0) || /* We cannot resume 'self' */
  965. (p_tcb == OSTCBCurPtr)) {
  966. CPU_CRITICAL_EXIT();
  967. *p_err = OS_ERR_TASK_RESUME_SELF;
  968. return;
  969. }
  970. #endif
  971. *p_err = OS_ERR_NONE;
  972. switch (p_tcb->TaskState) {
  973. case OS_TASK_STATE_RDY:
  974. case OS_TASK_STATE_DLY:
  975. case OS_TASK_STATE_PEND:
  976. case OS_TASK_STATE_PEND_TIMEOUT:
  977. CPU_CRITICAL_EXIT();
  978. *p_err = OS_ERR_TASK_NOT_SUSPENDED;
  979. break;
  980. case OS_TASK_STATE_SUSPENDED:
  981. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  982. p_tcb->SuspendCtr--;
  983. if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
  984. p_tcb->TaskState = OS_TASK_STATE_RDY;
  985. OS_TaskRdy(p_tcb);
  986. }
  987. OS_CRITICAL_EXIT_NO_SCHED();
  988. break;
  989. case OS_TASK_STATE_DLY_SUSPENDED:
  990. p_tcb->SuspendCtr--;
  991. if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
  992. p_tcb->TaskState = OS_TASK_STATE_DLY;
  993. }
  994. CPU_CRITICAL_EXIT();
  995. break;
  996. case OS_TASK_STATE_PEND_SUSPENDED:
  997. p_tcb->SuspendCtr--;
  998. if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
  999. p_tcb->TaskState = OS_TASK_STATE_PEND;
  1000. }
  1001. CPU_CRITICAL_EXIT();
  1002. break;
  1003. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  1004. p_tcb->SuspendCtr--;
  1005. if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
  1006. p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
  1007. }
  1008. CPU_CRITICAL_EXIT();
  1009. break;
  1010. default:
  1011. CPU_CRITICAL_EXIT();
  1012. *p_err = OS_ERR_STATE_INVALID;
  1013. return;
  1014. }
  1015. OSSched();
  1016. }
  1017. #endif
  1018. /*$PAGE*/
  1019. /*
  1020. ************************************************************************************************************************
  1021. * WAIT FOR A TASK SEMAPHORE
  1022. *
  1023. * Description: This function is called to block the current task until a signal is sent by another task or ISR.
  1024. *
  1025. * Arguments : timeout is the amount of time you are will to wait for the signal
  1026. *
  1027. * opt determines whether the user wants to block if a semaphore post was not received:
  1028. *
  1029. * OS_OPT_PEND_BLOCKING
  1030. * OS_OPT_PEND_NON_BLOCKING
  1031. *
  1032. * p_ts is a pointer to a variable that will receive the timestamp of when the semaphore was posted
  1033. * or pend aborted. If you pass a NULL pointer (i.e. (CPU_TS *)0) then you will not get the
  1034. * timestamp. In other words, passing a NULL pointer is valid and indicates that you don't
  1035. * need the timestamp.
  1036. *
  1037. * p_err is a pointer to an error code that will be set by this function
  1038. *
  1039. * OS_ERR_NONE The call was successful and your task received a message.
  1040. * OS_ERR_PEND_ABORT
  1041. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  1042. * OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but no signal was received
  1043. * OS_ERR_SCHED_LOCKED If the scheduler is locked
  1044. * OS_ERR_STATUS_INVALID If the pend status is invalid
  1045. * OS_ERR_TIMEOUT A message was not received within the specified timeout
  1046. * would lead to a suspension.
  1047. *
  1048. * Returns : The current count of signals the task received, 0 if none.
  1049. ************************************************************************************************************************
  1050. */
  1051. OS_SEM_CTR OSTaskSemPend (OS_TICK timeout,
  1052. OS_OPT opt,
  1053. CPU_TS *p_ts,
  1054. OS_ERR *p_err)
  1055. {
  1056. OS_SEM_CTR ctr;
  1057. CPU_SR_ALLOC();
  1058. #ifdef OS_SAFETY_CRITICAL
  1059. if (p_err == (OS_ERR *)0) {
  1060. OS_SAFETY_CRITICAL_EXCEPTION();
  1061. return ((OS_SEM_CTR)0);
  1062. }
  1063. #endif
  1064. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  1065. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
  1066. *p_err = OS_ERR_PEND_ISR;
  1067. return ((OS_SEM_CTR)0);
  1068. }
  1069. #endif
  1070. if (p_ts != (CPU_TS *)0) {
  1071. *p_ts = (CPU_TS )0; /* Initialize the returned timestamp */
  1072. }
  1073. CPU_CRITICAL_ENTER();
  1074. if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)0) { /* See if task already been signaled */
  1075. OSTCBCurPtr->SemCtr--;
  1076. ctr = OSTCBCurPtr->SemCtr;
  1077. if (p_ts != (CPU_TS *)0) {
  1078. *p_ts = OSTCBCurPtr->TS;
  1079. }
  1080. #if OS_CFG_TASK_PROFILE_EN > 0u
  1081. OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
  1082. if (OSTCBCurPtr->SemPendTime > OSTCBCurPtr->SemPendTimeMax) {
  1083. OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
  1084. }
  1085. #endif
  1086. CPU_CRITICAL_EXIT();
  1087. *p_err = OS_ERR_NONE;
  1088. return (ctr);
  1089. }
  1090. if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */
  1091. CPU_CRITICAL_EXIT();
  1092. *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */
  1093. return ((OS_SEM_CTR)0);
  1094. } else { /* Yes */
  1095. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */
  1096. CPU_CRITICAL_EXIT();
  1097. *p_err = OS_ERR_SCHED_LOCKED;
  1098. return ((OS_SEM_CTR)0);
  1099. }
  1100. }
  1101. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
  1102. OS_Pend((OS_PEND_DATA *)0, /* Block task pending on Signal */
  1103. (OS_PEND_OBJ *)0,
  1104. (OS_STATE )OS_TASK_PEND_ON_TASK_SEM,
  1105. (OS_TICK )timeout);
  1106. OS_CRITICAL_EXIT_NO_SCHED();
  1107. OSSched(); /* Find next highest priority task ready to run */
  1108. CPU_CRITICAL_ENTER();
  1109. switch (OSTCBCurPtr->PendStatus) { /* See if we timed-out or aborted */
  1110. case OS_STATUS_PEND_OK:
  1111. if (p_ts != (CPU_TS *)0) {
  1112. *p_ts = OSTCBCurPtr->TS;
  1113. #if OS_CFG_TASK_PROFILE_EN > 0u
  1114. OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
  1115. if (OSTCBCurPtr->SemPendTime > OSTCBCurPtr->SemPendTimeMax) {
  1116. OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
  1117. }
  1118. #endif
  1119. }
  1120. *p_err = OS_ERR_NONE;
  1121. break;
  1122. case OS_STATUS_PEND_ABORT:
  1123. if (p_ts != (CPU_TS *)0) {
  1124. *p_ts = OSTCBCurPtr->TS;
  1125. }
  1126. *p_err = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
  1127. break;
  1128. case OS_STATUS_PEND_TIMEOUT:
  1129. if (p_ts != (CPU_TS *)0) {
  1130. *p_ts = (CPU_TS )0;
  1131. }
  1132. *p_err = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
  1133. break;
  1134. default:
  1135. *p_err = OS_ERR_STATUS_INVALID;
  1136. break;
  1137. }
  1138. ctr = OSTCBCurPtr->SemCtr;
  1139. CPU_CRITICAL_EXIT();
  1140. return (ctr);
  1141. }
  1142. /*$PAGE*/
  1143. /*
  1144. ************************************************************************************************************************
  1145. * ABORT WAITING FOR A SIGNAL
  1146. *
  1147. * Description: This function aborts & readies the task specified. This function should be used to fault-abort the wait
  1148. * for a signal, rather than to normally post the signal to the task via OSTaskSemPost().
  1149. *
  1150. * Arguments : p_tcb is a pointer to the task to pend abort
  1151. *
  1152. * opt provides options for this function:
  1153. *
  1154. * OS_OPT_POST_NONE No option selected
  1155. * OS_OPT_POST_NO_SCHED Indicates that the scheduler will not be called.
  1156. *
  1157. * p_err is a pointer to a variable that will contain an error code returned by this function.
  1158. *
  1159. * OS_ERR_NONE If the task was readied and informed of the aborted wait
  1160. * OS_ERR_PEND_ABORT_ISR If you tried calling this function from an ISR
  1161. * OS_ERR_PEND_ABORT_NONE If the task was not waiting for a signal
  1162. * OS_ERR_PEND_ABORT_SELF If you attempted to pend abort the calling task. This is not
  1163. * possible since the calling task cannot be pending because it's
  1164. * running.
  1165. *
  1166. * Returns : == DEF_FALSE if task was not waiting for a message, or upon error.
  1167. * == DEF_TRUE if task was waiting for a message and was readied and informed.
  1168. ************************************************************************************************************************
  1169. */
  1170. #if OS_CFG_TASK_SEM_PEND_ABORT_EN > 0u
  1171. CPU_BOOLEAN OSTaskSemPendAbort (OS_TCB *p_tcb,
  1172. OS_OPT opt,
  1173. OS_ERR *p_err)
  1174. {
  1175. CPU_TS ts;
  1176. CPU_SR_ALLOC();
  1177. #ifdef OS_SAFETY_CRITICAL
  1178. if (p_err == (OS_ERR *)0) {
  1179. OS_SAFETY_CRITICAL_EXCEPTION();
  1180. return (DEF_FALSE);
  1181. }
  1182. #endif
  1183. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  1184. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from ISR ... */
  1185. *p_err = OS_ERR_PEND_ABORT_ISR; /* ... can't Pend Abort from an ISR */
  1186. return (DEF_FALSE);
  1187. }
  1188. #endif
  1189. CPU_CRITICAL_ENTER();
  1190. if ((p_tcb == (OS_TCB *)0) || /* Pend abort self? */
  1191. (p_tcb == OSTCBCurPtr)) {
  1192. CPU_CRITICAL_EXIT(); /* ... doesn't make sense! */
  1193. *p_err = OS_ERR_PEND_ABORT_SELF;
  1194. return (DEF_FALSE);
  1195. }
  1196. if (p_tcb->PendOn != OS_TASK_PEND_ON_TASK_SEM) { /* Is task waiting for a signal? */
  1197. CPU_CRITICAL_EXIT();
  1198. *p_err = OS_ERR_PEND_ABORT_NONE;
  1199. return (DEF_FALSE);
  1200. }
  1201. CPU_CRITICAL_EXIT();
  1202. OS_CRITICAL_ENTER();
  1203. ts = OS_TS_GET();
  1204. OS_PendAbort((OS_PEND_OBJ *)0,
  1205. p_tcb,
  1206. ts);
  1207. OS_CRITICAL_EXIT_NO_SCHED();
  1208. if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
  1209. OSSched(); /* Run the scheduler */
  1210. }
  1211. *p_err = OS_ERR_NONE;
  1212. return (DEF_TRUE);
  1213. }
  1214. #endif
  1215. /*$PAGE*/
  1216. /*
  1217. ************************************************************************************************************************
  1218. * SIGNAL A TASK
  1219. *
  1220. * Description: This function is called to signal a task waiting for a signal.
  1221. *
  1222. * Arguments : p_tcb is the pointer to the TCB of the task to signal. A NULL pointer indicates that you are sending
  1223. * a signal to yourself.
  1224. *
  1225. * opt determines the type of POST performed:
  1226. *
  1227. * OS_OPT_POST_NONE No option
  1228. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  1229. *
  1230. * p_err is a pointer to an error code returned by this function:
  1231. *
  1232. * OS_ERR_NONE If the requested task is signaled
  1233. * OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow.
  1234. *
  1235. * Returns : The current value of the task's signal counter or 0 if called from an ISR
  1236. ************************************************************************************************************************
  1237. */
  1238. OS_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb,
  1239. OS_OPT opt,
  1240. OS_ERR *p_err)
  1241. {
  1242. OS_SEM_CTR ctr;
  1243. CPU_TS ts;
  1244. #ifdef OS_SAFETY_CRITICAL
  1245. if (p_err == (OS_ERR *)0) {
  1246. OS_SAFETY_CRITICAL_EXCEPTION();
  1247. return ((OS_SEM_CTR)0);
  1248. }
  1249. #endif
  1250. ts = OS_TS_GET(); /* Get timestamp */
  1251. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  1252. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from an ISR */
  1253. OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_SIGNAL, /* Post to ISR queue */
  1254. (void *)p_tcb,
  1255. (void *)0,
  1256. (OS_MSG_SIZE)0,
  1257. (OS_FLAGS )0,
  1258. (OS_OPT )0,
  1259. (CPU_TS )ts,
  1260. (OS_ERR *)p_err);
  1261. return ((OS_SEM_CTR)0);
  1262. }
  1263. #endif
  1264. ctr = OS_TaskSemPost(p_tcb,
  1265. opt,
  1266. ts,
  1267. p_err);
  1268. return (ctr);
  1269. }
  1270. /*$PAGE*/
  1271. /*
  1272. ************************************************************************************************************************
  1273. * SET THE SIGNAL COUNTER OF A TASK
  1274. *
  1275. * Description: This function is called to clear the signal counter
  1276. *
  1277. * Arguments : p_tcb is the pointer to the TCB of the task to clear the counter. If you specify a NULL pointer
  1278. * then the signal counter of the current task will be cleared.
  1279. *
  1280. * cnt is the desired value of the semaphore counter
  1281. *
  1282. * p_err is a pointer to an error code returned by this function
  1283. *
  1284. * OS_ERR_NONE if the signal counter of the requested task is cleared
  1285. * OS_ERR_SET_ISR if the function was called from an ISR
  1286. *
  1287. * Returns : none
  1288. ************************************************************************************************************************
  1289. */
  1290. OS_SEM_CTR OSTaskSemSet (OS_TCB *p_tcb,
  1291. OS_SEM_CTR cnt,
  1292. OS_ERR *p_err)
  1293. {
  1294. OS_SEM_CTR ctr;
  1295. CPU_SR_ALLOC();
  1296. #ifdef OS_SAFETY_CRITICAL
  1297. if (p_err == (OS_ERR *)0) {
  1298. OS_SAFETY_CRITICAL_EXCEPTION();
  1299. return ((OS_SEM_CTR)0);
  1300. }
  1301. #endif
  1302. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  1303. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
  1304. *p_err = OS_ERR_SET_ISR;
  1305. return ((OS_SEM_CTR)0);
  1306. }
  1307. #endif
  1308. CPU_CRITICAL_ENTER();
  1309. if (p_tcb == (OS_TCB *)0) {
  1310. p_tcb = OSTCBCurPtr;
  1311. }
  1312. ctr = p_tcb->SemCtr;
  1313. p_tcb->SemCtr = (OS_SEM_CTR)cnt;
  1314. CPU_CRITICAL_EXIT();
  1315. *p_err = OS_ERR_NONE;
  1316. return (ctr);
  1317. }
  1318. /*$PAGE*/
  1319. /*
  1320. ************************************************************************************************************************
  1321. * STACK CHECKING
  1322. *
  1323. * Description: This function is called to calculate the amount of free memory left on the specified task's stack.
  1324. *
  1325. * Arguments : p_tcb is a pointer to the TCB of the task to check. If you specify a NULL pointer then
  1326. * you are specifying that you want to check the stack of the current task.
  1327. *
  1328. * p_free is a pointer to a variable that will receive the number of free 'entries' on the task's stack.
  1329. *
  1330. * p_used is a pointer to a variable that will receive the number of used 'entries' on the task's stack.
  1331. *
  1332. * p_err is a pointer to a variable that will contain an error code.
  1333. *
  1334. * OS_ERR_NONE upon success
  1335. * OS_ERR_PTR_INVALID if either 'p_free' or 'p_used' are NULL pointers
  1336. * OS_ERR_TASK_NOT_EXIST if the stack pointer of the task is a NULL pointer
  1337. * OS_ERR_TASK_OPT if you did NOT specified OS_OPT_TASK_STK_CHK when the task
  1338. * was created
  1339. * OS_ERR_TASK_STK_CHK_ISR you called this function from an ISR
  1340. ************************************************************************************************************************
  1341. */
  1342. #if OS_CFG_STAT_TASK_STK_CHK_EN > 0u
  1343. void OSTaskStkChk (OS_TCB *p_tcb,
  1344. CPU_STK_SIZE *p_free,
  1345. CPU_STK_SIZE *p_used,
  1346. OS_ERR *p_err)
  1347. {
  1348. CPU_STK_SIZE free_stk;
  1349. CPU_STK *p_stk;
  1350. CPU_SR_ALLOC();
  1351. #ifdef OS_SAFETY_CRITICAL
  1352. if (p_err == (OS_ERR *)0) {
  1353. OS_SAFETY_CRITICAL_EXCEPTION();
  1354. return;
  1355. }
  1356. #endif
  1357. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  1358. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to check stack from ISR */
  1359. *p_err = OS_ERR_TASK_STK_CHK_ISR;
  1360. return;
  1361. }
  1362. #endif
  1363. #if OS_CFG_ARG_CHK_EN > 0u
  1364. if (p_free == (CPU_STK_SIZE*)0) { /* User must specify valid destinations for the sizes */
  1365. *p_err = OS_ERR_PTR_INVALID;
  1366. return;
  1367. }
  1368. if (p_used == (CPU_STK_SIZE*)0) {
  1369. *p_err = OS_ERR_PTR_INVALID;
  1370. return;
  1371. }
  1372. #endif
  1373. CPU_CRITICAL_ENTER();
  1374. if (p_tcb == (OS_TCB *)0) { /* Check the stack of the current task? */
  1375. p_tcb = OSTCBCurPtr; /* Yes */
  1376. }
  1377. if (p_tcb->StkPtr == (CPU_STK*)0) { /* Make sure task exist */
  1378. CPU_CRITICAL_EXIT();
  1379. *p_free = (CPU_STK_SIZE)0;
  1380. *p_used = (CPU_STK_SIZE)0;
  1381. *p_err = OS_ERR_TASK_NOT_EXIST;
  1382. return;
  1383. }
  1384. if ((p_tcb->Opt & OS_OPT_TASK_STK_CHK) == (OS_OPT)0) { /* Make sure stack checking option is set */
  1385. CPU_CRITICAL_EXIT();
  1386. *p_free = (CPU_STK_SIZE)0;
  1387. *p_used = (CPU_STK_SIZE)0;
  1388. *p_err = OS_ERR_TASK_OPT;
  1389. return;
  1390. }
  1391. CPU_CRITICAL_EXIT();
  1392. free_stk = 0u;
  1393. #if CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO
  1394. p_stk = p_tcb->StkBasePtr; /* Start at the lowest memory and go up */
  1395. while (*p_stk == (CPU_STK)0) { /* Compute the number of zero entries on the stk */
  1396. p_stk++;
  1397. free_stk++;
  1398. }
  1399. #else
  1400. p_stk = p_tcb->StkBasePtr + p_tcb->StkSize - 1u; /* Start at the highest memory and go down */
  1401. while (*p_stk == (CPU_STK)0) {
  1402. free_stk++;
  1403. p_stk--;
  1404. }
  1405. #endif
  1406. *p_free = free_stk;
  1407. *p_used = (p_tcb->StkSize - free_stk); /* Compute number of entries used on the stack */
  1408. *p_err = OS_ERR_NONE;
  1409. }
  1410. #endif
  1411. /*$PAGE*/
  1412. /*
  1413. ************************************************************************************************************************
  1414. * SUSPEND A TASK
  1415. *
  1416. * Description: This function is called to suspend a task. The task can be the calling task if 'p_tcb' is a NULL pointer
  1417. * or the pointer to the TCB of the calling task.
  1418. *
  1419. * Arguments : p_tcb is a pointer to the TCB to suspend.
  1420. * If p_tcb is a NULL pointer then, suspend the current task.
  1421. *
  1422. * p_err is a pointer to a variable that will receive an error code from this function.
  1423. *
  1424. * OS_ERR_NONE if the requested task is suspended
  1425. * OS_ERR_SCHED_LOCKED you can't suspend the current task is the scheduler is
  1426. * locked
  1427. * OS_ERR_TASK_SUSPEND_ISR if you called this function from an ISR
  1428. * OS_ERR_TASK_SUSPEND_IDLE if you attempted to suspend the idle task which is not
  1429. * allowed.
  1430. * OS_ERR_TASK_SUSPEND_INT_HANDLER if you attempted to suspend the idle task which is not
  1431. * allowed.
  1432. *
  1433. * Note(s) : 1) You should use this function with great care. If you suspend a task that is waiting for an event
  1434. * (i.e. a message, a semaphore, a queue ...) you will prevent this task from running when the event
  1435. * arrives.
  1436. ************************************************************************************************************************
  1437. */
  1438. #if OS_CFG_TASK_SUSPEND_EN > 0u
  1439. void OSTaskSuspend (OS_TCB *p_tcb,
  1440. OS_ERR *p_err)
  1441. {
  1442. CPU_SR_ALLOC();
  1443. #ifdef OS_SAFETY_CRITICAL
  1444. if (p_err == (OS_ERR *)0) {
  1445. OS_SAFETY_CRITICAL_EXCEPTION();
  1446. return;
  1447. }
  1448. #endif
  1449. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  1450. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
  1451. *p_err = OS_ERR_TASK_SUSPEND_ISR;
  1452. return;
  1453. }
  1454. #endif
  1455. if (p_tcb == &OSIdleTaskTCB) { /* Make sure not suspending the idle task */
  1456. *p_err = OS_ERR_TASK_SUSPEND_IDLE;
  1457. return;
  1458. }
  1459. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  1460. if (p_tcb == &OSIntQTaskTCB) { /* Not allowed to suspend the ISR handler task */
  1461. *p_err = OS_ERR_TASK_SUSPEND_INT_HANDLER;
  1462. return;
  1463. }
  1464. #endif
  1465. CPU_CRITICAL_ENTER();
  1466. if (p_tcb == (OS_TCB *)0) { /* See if specified to suspend self */
  1467. p_tcb = OSTCBCurPtr;
  1468. }
  1469. if (p_tcb == OSTCBCurPtr) {
  1470. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't suspend when the scheduler is locked */
  1471. CPU_CRITICAL_EXIT();
  1472. *p_err = OS_ERR_SCHED_LOCKED;
  1473. return;
  1474. }
  1475. }
  1476. *p_err = OS_ERR_NONE;
  1477. switch (p_tcb->TaskState) {
  1478. case OS_TASK_STATE_RDY:
  1479. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  1480. p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
  1481. p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
  1482. OS_RdyListRemove(p_tcb);
  1483. OS_CRITICAL_EXIT_NO_SCHED();
  1484. break;
  1485. case OS_TASK_STATE_DLY:
  1486. p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED;
  1487. p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
  1488. CPU_CRITICAL_EXIT();
  1489. break;
  1490. case OS_TASK_STATE_PEND:
  1491. p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED;
  1492. p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
  1493. CPU_CRITICAL_EXIT();
  1494. break;
  1495. case OS_TASK_STATE_PEND_TIMEOUT:
  1496. p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;
  1497. p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
  1498. CPU_CRITICAL_EXIT();
  1499. break;
  1500. case OS_TASK_STATE_SUSPENDED:
  1501. case OS_TASK_STATE_DLY_SUSPENDED:
  1502. case OS_TASK_STATE_PEND_SUSPENDED:
  1503. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  1504. p_tcb->SuspendCtr++;
  1505. CPU_CRITICAL_EXIT();
  1506. break;
  1507. default:
  1508. CPU_CRITICAL_EXIT();
  1509. *p_err = OS_ERR_STATE_INVALID;
  1510. return;
  1511. }
  1512. OSSched();
  1513. }
  1514. #endif
  1515. /*$PAGE*/
  1516. /*
  1517. ************************************************************************************************************************
  1518. * CHANGE A TASK'S TIME SLICE
  1519. *
  1520. * Description: This function is called to change the value of the task's specific time slice.
  1521. *
  1522. * Arguments : p_tcb is the pointer to the TCB of the task to change. If you specify an NULL pointer, the current
  1523. * task is assumed.
  1524. *
  1525. * time_quanta is the number of ticks before the CPU is taken away when round-robin scheduling is enabled.
  1526. *
  1527. * p_err is a pointer to an error code returned by this function:
  1528. *
  1529. * OS_ERR_NONE upon success
  1530. * OS_ERR_SET_ISR if you called this function from an ISR
  1531. *
  1532. * Returns : none
  1533. ************************************************************************************************************************
  1534. */
  1535. #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
  1536. void OSTaskTimeQuantaSet (OS_TCB *p_tcb,
  1537. OS_TICK time_quanta,
  1538. OS_ERR *p_err)
  1539. {
  1540. CPU_SR_ALLOC();
  1541. #ifdef OS_SAFETY_CRITICAL
  1542. if (p_err == (OS_ERR *)0) {
  1543. OS_SAFETY_CRITICAL_EXCEPTION();
  1544. return;
  1545. }
  1546. #endif
  1547. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  1548. if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't call this function from an ISR */
  1549. *p_err = OS_ERR_SET_ISR;
  1550. return;
  1551. }
  1552. #endif
  1553. CPU_CRITICAL_ENTER();
  1554. if (p_tcb == (OS_TCB *)0) {
  1555. p_tcb = OSTCBCurPtr;
  1556. }
  1557. if (time_quanta == 0u) {
  1558. p_tcb->TimeQuanta = OSSchedRoundRobinDfltTimeQuanta;
  1559. } else {
  1560. p_tcb->TimeQuanta = time_quanta;
  1561. }
  1562. if (p_tcb->TimeQuanta > p_tcb->TimeQuantaCtr) {
  1563. p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;
  1564. }
  1565. CPU_CRITICAL_EXIT();
  1566. *p_err = OS_ERR_NONE;
  1567. }
  1568. #endif
  1569. /*$PAGE*/
  1570. /*
  1571. ************************************************************************************************************************
  1572. * ADD/REMOVE TASK TO/FROM DEBUG LIST
  1573. *
  1574. * Description: These functions are called by uC/OS-III to add or remove an OS_TCB from the debug list.
  1575. *
  1576. * Arguments : p_tcb is a pointer to the OS_TCB to add/remove
  1577. *
  1578. * Returns : none
  1579. *
  1580. * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
  1581. ************************************************************************************************************************
  1582. */
  1583. #if OS_CFG_DBG_EN > 0u
  1584. void OS_TaskDbgListAdd (OS_TCB *p_tcb)
  1585. {
  1586. p_tcb->DbgPrevPtr = (OS_TCB *)0;
  1587. if (OSTaskDbgListPtr == (OS_TCB *)0) {
  1588. p_tcb->DbgNextPtr = (OS_TCB *)0;
  1589. } else {
  1590. p_tcb->DbgNextPtr = OSTaskDbgListPtr;
  1591. OSTaskDbgListPtr->DbgPrevPtr = p_tcb;
  1592. }
  1593. OSTaskDbgListPtr = p_tcb;
  1594. }
  1595. void OS_TaskDbgListRemove (OS_TCB *p_tcb)
  1596. {
  1597. OS_TCB *p_tcb_next;
  1598. OS_TCB *p_tcb_prev;
  1599. p_tcb_prev = p_tcb->DbgPrevPtr;
  1600. p_tcb_next = p_tcb->DbgNextPtr;
  1601. if (p_tcb_prev == (OS_TCB *)0) {
  1602. OSTaskDbgListPtr = p_tcb_next;
  1603. if (p_tcb_next != (OS_TCB *)0) {
  1604. p_tcb_next->DbgPrevPtr = (OS_TCB *)0;
  1605. }
  1606. p_tcb->DbgNextPtr = (OS_TCB *)0;
  1607. } else if (p_tcb_next == (OS_TCB *)0) {
  1608. p_tcb_prev->DbgNextPtr = (OS_TCB *)0;
  1609. p_tcb->DbgPrevPtr = (OS_TCB *)0;
  1610. } else {
  1611. p_tcb_prev->DbgNextPtr = p_tcb_next;
  1612. p_tcb_next->DbgPrevPtr = p_tcb_prev;
  1613. p_tcb->DbgNextPtr = (OS_TCB *)0;
  1614. p_tcb->DbgPrevPtr = (OS_TCB *)0;
  1615. }
  1616. }
  1617. #endif
  1618. /*$PAGE*/
  1619. /*
  1620. ************************************************************************************************************************
  1621. * TASK MANAGER INITIALIZATION
  1622. *
  1623. * Description: This function is called by OSInit() to initialize the task management.
  1624. *
  1625. * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
  1626. *
  1627. * OS_ERR_NONE the call was successful
  1628. *
  1629. * Returns : none
  1630. *
  1631. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  1632. ************************************************************************************************************************
  1633. */
  1634. void OS_TaskInit (OS_ERR *p_err)
  1635. {
  1636. #ifdef OS_SAFETY_CRITICAL
  1637. if (p_err == (OS_ERR *)0) {
  1638. OS_SAFETY_CRITICAL_EXCEPTION();
  1639. return;
  1640. }
  1641. #endif
  1642. #if OS_CFG_DBG_EN > 0u
  1643. OSTaskDbgListPtr = (OS_TCB *)0;
  1644. #endif
  1645. OSTaskQty = (OS_OBJ_QTY )0; /* Clear the number of tasks */
  1646. OSTaskCtxSwCtr = (OS_CTX_SW_CTR)0; /* Clear the context switch counter */
  1647. *p_err = OS_ERR_NONE;
  1648. }
  1649. /*$PAGE*/
  1650. /*
  1651. ************************************************************************************************************************
  1652. * INITIALIZE TCB FIELDS
  1653. *
  1654. * Description: This function is called to initialize a TCB to default values
  1655. *
  1656. * Arguments : p_tcb is a pointer to the TCB to initialize
  1657. *
  1658. * Returns : none
  1659. *
  1660. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  1661. ************************************************************************************************************************
  1662. */
  1663. void OS_TaskInitTCB (OS_TCB *p_tcb)
  1664. {
  1665. #if OS_CFG_TASK_REG_TBL_SIZE > 0u
  1666. OS_REG_ID id;
  1667. #endif
  1668. #if OS_CFG_TASK_PROFILE_EN > 0u
  1669. CPU_TS ts;
  1670. #endif
  1671. p_tcb->StkPtr = (CPU_STK *)0;
  1672. p_tcb->StkLimitPtr = (CPU_STK *)0;
  1673. p_tcb->ExtPtr = (void *)0;
  1674. p_tcb->NextPtr = (OS_TCB *)0;
  1675. p_tcb->PrevPtr = (OS_TCB *)0;
  1676. p_tcb->TickNextPtr = (OS_TCB *)0;
  1677. p_tcb->TickPrevPtr = (OS_TCB *)0;
  1678. p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0;
  1679. p_tcb->NamePtr = (CPU_CHAR *)((void *)"?Task");
  1680. p_tcb->StkBasePtr = (CPU_STK *)0;
  1681. p_tcb->TaskEntryAddr = (OS_TASK_PTR )0;
  1682. p_tcb->TaskEntryArg = (void *)0;
  1683. #if (OS_CFG_PEND_MULTI_EN > 0u)
  1684. p_tcb->PendDataTblPtr = (OS_PEND_DATA *)0;
  1685. p_tcb->PendDataTblEntries = (OS_OBJ_QTY )0u;
  1686. #endif
  1687. p_tcb->TS = (CPU_TS )0u;
  1688. #if (OS_MSG_EN > 0u)
  1689. p_tcb->MsgPtr = (void *)0;
  1690. p_tcb->MsgSize = (OS_MSG_SIZE )0u;
  1691. #endif
  1692. #if OS_CFG_TASK_Q_EN > 0u
  1693. OS_MsgQInit(&p_tcb->MsgQ,
  1694. (OS_MSG_QTY)0u);
  1695. #if OS_CFG_TASK_PROFILE_EN > 0u
  1696. p_tcb->MsgQPendTime = (CPU_TS )0u;
  1697. p_tcb->MsgQPendTimeMax = (CPU_TS )0u;
  1698. #endif
  1699. #endif
  1700. #if OS_CFG_FLAG_EN > 0u
  1701. p_tcb->FlagsPend = (OS_FLAGS )0u;
  1702. p_tcb->FlagsOpt = (OS_OPT )0u;
  1703. p_tcb->FlagsRdy = (OS_FLAGS )0u;
  1704. #endif
  1705. #if OS_CFG_TASK_REG_TBL_SIZE > 0u
  1706. for (id = 0u; id < OS_CFG_TASK_REG_TBL_SIZE; id++) {
  1707. p_tcb->RegTbl[id] = (OS_REG)0u;
  1708. }
  1709. #endif
  1710. p_tcb->SemCtr = (OS_SEM_CTR )0u;
  1711. #if OS_CFG_TASK_PROFILE_EN > 0u
  1712. p_tcb->SemPendTime = (CPU_TS )0u;
  1713. p_tcb->SemPendTimeMax = (CPU_TS )0u;
  1714. #endif
  1715. p_tcb->StkSize = (CPU_STK_SIZE )0u;
  1716. #if OS_CFG_TASK_SUSPEND_EN > 0u
  1717. p_tcb->SuspendCtr = (OS_NESTING_CTR )0u;
  1718. #endif
  1719. #if OS_CFG_STAT_TASK_STK_CHK_EN > 0u
  1720. p_tcb->StkFree = (CPU_STK_SIZE )0u;
  1721. p_tcb->StkUsed = (CPU_STK_SIZE )0u;
  1722. #endif
  1723. p_tcb->Opt = (OS_OPT )0u;
  1724. p_tcb->TickCtrPrev = (OS_TICK )OS_TICK_TH_INIT;
  1725. p_tcb->TickCtrMatch = (OS_TICK )0u;
  1726. p_tcb->TickRemain = (OS_TICK )0u;
  1727. p_tcb->TimeQuanta = (OS_TICK )0u;
  1728. p_tcb->TimeQuantaCtr = (OS_TICK )0u;
  1729. #if OS_CFG_TASK_PROFILE_EN > 0u
  1730. p_tcb->CPUUsage = (OS_CPU_USAGE )0u;
  1731. p_tcb->CtxSwCtr = (OS_CTX_SW_CTR )0u;
  1732. p_tcb->CyclesDelta = (CPU_TS )0u;
  1733. ts = OS_TS_GET(); /* Read the current timestamp and save */
  1734. p_tcb->CyclesStart = ts;
  1735. p_tcb->CyclesTotal = (OS_CYCLES )0u;
  1736. #endif
  1737. #ifdef CPU_CFG_INT_DIS_MEAS_EN
  1738. p_tcb->IntDisTimeMax = (CPU_TS )0u;
  1739. #endif
  1740. #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
  1741. p_tcb->SchedLockTimeMax = (CPU_TS )0u;
  1742. #endif
  1743. p_tcb->PendOn = (OS_STATE )OS_TASK_PEND_ON_NOTHING;
  1744. p_tcb->PendStatus = (OS_STATUS )OS_STATUS_PEND_OK;
  1745. p_tcb->TaskState = (OS_STATE )OS_TASK_STATE_RDY;
  1746. p_tcb->Prio = (OS_PRIO )OS_PRIO_INIT;
  1747. #if OS_CFG_DBG_EN > 0u
  1748. p_tcb->DbgPrevPtr = (OS_TCB *)0;
  1749. p_tcb->DbgNextPtr = (OS_TCB *)0;
  1750. p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" ");
  1751. #endif
  1752. }
  1753. /*$PAGE*/
  1754. /*
  1755. ************************************************************************************************************************
  1756. * POST MESSAGE TO A TASK
  1757. *
  1758. * Description: This function sends a message to a task
  1759. *
  1760. * Arguments : p_tcb is a pointer to the TCB of the task receiving a message. If you specify a NULL pointer then
  1761. * the message will be posted to the task's queue of the calling task. In other words, you'd be
  1762. * posting a message to yourself.
  1763. *
  1764. * p_void is a pointer to the message to send.
  1765. *
  1766. * msg_size is the size of the message sent (in #bytes)
  1767. *
  1768. * opt specifies whether the post will be FIFO or LIFO:
  1769. *
  1770. * OS_OPT_POST_FIFO Post at the end of the queue
  1771. * OS_OPT_POST_LIFO Post at the front of the queue
  1772. *
  1773. * OS_OPT_POST_NO_SCHED Do not run the scheduler after the post
  1774. *
  1775. * Note(s): 1) OS_OPT_POST_NO_SCHED can be added with one of the other options.
  1776. *
  1777. *
  1778. * ts is a timestamp indicating when the post occurred.
  1779. *
  1780. * p_err is a pointer to a variable that will hold the error code associated
  1781. * with the outcome of this call. Errors can be:
  1782. *
  1783. * OS_ERR_NONE The call was successful and the message was sent
  1784. * OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs available from the pool
  1785. * OS_ERR_Q_MAX If the queue is full
  1786. * OS_ERR_STATE_INVALID If the task is in an invalid state. This should never happen
  1787. * and if it does, would be considered a system failure.
  1788. *
  1789. * Returns : none
  1790. *
  1791. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  1792. ************************************************************************************************************************
  1793. */
  1794. #if OS_CFG_TASK_Q_EN > 0u
  1795. void OS_TaskQPost (OS_TCB *p_tcb,
  1796. void *p_void,
  1797. OS_MSG_SIZE msg_size,
  1798. OS_OPT opt,
  1799. CPU_TS ts,
  1800. OS_ERR *p_err)
  1801. {
  1802. CPU_SR_ALLOC();
  1803. OS_CRITICAL_ENTER();
  1804. if (p_tcb == (OS_TCB *)0) { /* Post msg to 'self'? */
  1805. p_tcb = OSTCBCurPtr;
  1806. }
  1807. *p_err = OS_ERR_NONE; /* Assume we won't have any errors */
  1808. switch (p_tcb->TaskState) {
  1809. case OS_TASK_STATE_RDY:
  1810. case OS_TASK_STATE_DLY:
  1811. case OS_TASK_STATE_SUSPENDED:
  1812. case OS_TASK_STATE_DLY_SUSPENDED:
  1813. OS_MsgQPut(&p_tcb->MsgQ, /* Deposit the message in the queue */
  1814. p_void,
  1815. msg_size,
  1816. opt,
  1817. ts,
  1818. p_err);
  1819. OS_CRITICAL_EXIT();
  1820. break;
  1821. case OS_TASK_STATE_PEND:
  1822. case OS_TASK_STATE_PEND_TIMEOUT:
  1823. case OS_TASK_STATE_PEND_SUSPENDED:
  1824. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  1825. if (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_Q) { /* Is task waiting for a message to be sent to it? */
  1826. OS_Post((OS_PEND_OBJ *)0,
  1827. p_tcb,
  1828. p_void,
  1829. msg_size,
  1830. ts);
  1831. OS_CRITICAL_EXIT_NO_SCHED();
  1832. if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0u) {
  1833. OSSched(); /* Run the scheduler */
  1834. }
  1835. } else {
  1836. OS_MsgQPut(&p_tcb->MsgQ, /* No, Task is pending on something else ... */
  1837. p_void, /* ... Deposit the message in the task's queue */
  1838. msg_size,
  1839. opt,
  1840. ts,
  1841. p_err);
  1842. OS_CRITICAL_EXIT();
  1843. }
  1844. break;
  1845. default:
  1846. OS_CRITICAL_EXIT();
  1847. *p_err = OS_ERR_STATE_INVALID;
  1848. break;
  1849. }
  1850. }
  1851. #endif
  1852. /*$PAGE*/
  1853. /*
  1854. ************************************************************************************************************************
  1855. * CATCH ACCIDENTAL TASK RETURN
  1856. *
  1857. * Description: This function is called if a task accidentally returns without deleting itself. In other words, a task
  1858. * should either be an infinite loop or delete itself if it's done.
  1859. *
  1860. * Arguments : none
  1861. *
  1862. * Returns : none
  1863. *
  1864. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  1865. ************************************************************************************************************************
  1866. */
  1867. void OS_TaskReturn (void)
  1868. {
  1869. OS_ERR err;
  1870. OSTaskReturnHook(OSTCBCurPtr); /* Call hook to let user decide on what to do */
  1871. #if OS_CFG_TASK_DEL_EN > 0u
  1872. OSTaskDel((OS_TCB *)0, /* Delete task if it accidentally returns! */
  1873. (OS_ERR *)&err);
  1874. #else
  1875. for (;;) {
  1876. OSTimeDly((OS_TICK )OSCfg_TickRate_Hz,
  1877. (OS_OPT )OS_OPT_TIME_DLY,
  1878. (OS_ERR *)&err);
  1879. }
  1880. #endif
  1881. }
  1882. /*$PAGE*/
  1883. /*
  1884. ************************************************************************************************************************
  1885. * SIGNAL A TASK
  1886. *
  1887. * Description: This function is called to signal a task waiting for a signal.
  1888. *
  1889. * Arguments : p_tcb is the pointer to the TCB of the task to signal. A NULL pointer indicates that you are sending
  1890. * a signal to yourself.
  1891. *
  1892. * opt determines the type of POST performed:
  1893. *
  1894. * OS_OPT_POST_NONE No option
  1895. *
  1896. * OS_OPT_POST_NO_SCHED Do not call the scheduler
  1897. *
  1898. * ts is a timestamp indicating when the post occurred.
  1899. *
  1900. * p_err is a pointer to an error code returned by this function:
  1901. *
  1902. * OS_ERR_NONE If the requested task is signaled
  1903. * OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow.
  1904. * OS_ERR_STATE_INVALID If the task is in an invalid state. This should never happen
  1905. * and if it does, would be considered a system failure.
  1906. *
  1907. * Returns : The current value of the task's signal counter or 0 if called from an ISR
  1908. *
  1909. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  1910. ************************************************************************************************************************
  1911. */
  1912. OS_SEM_CTR OS_TaskSemPost (OS_TCB *p_tcb,
  1913. OS_OPT opt,
  1914. CPU_TS ts,
  1915. OS_ERR *p_err)
  1916. {
  1917. OS_SEM_CTR ctr;
  1918. CPU_SR_ALLOC();
  1919. OS_CRITICAL_ENTER();
  1920. if (p_tcb == (OS_TCB *)0) { /* Post signal to 'self'? */
  1921. p_tcb = OSTCBCurPtr;
  1922. }
  1923. p_tcb->TS = ts;
  1924. *p_err = OS_ERR_NONE; /* Assume we won't have any errors */
  1925. switch (p_tcb->TaskState) {
  1926. case OS_TASK_STATE_RDY:
  1927. case OS_TASK_STATE_DLY:
  1928. case OS_TASK_STATE_SUSPENDED:
  1929. case OS_TASK_STATE_DLY_SUSPENDED:
  1930. switch (sizeof(OS_SEM_CTR)) {
  1931. case 1u:
  1932. if (p_tcb->SemCtr == DEF_INT_08U_MAX_VAL) {
  1933. OS_CRITICAL_EXIT();
  1934. *p_err = OS_ERR_SEM_OVF;
  1935. return ((OS_SEM_CTR)0);
  1936. }
  1937. break;
  1938. case 2u:
  1939. if (p_tcb->SemCtr == DEF_INT_16U_MAX_VAL) {
  1940. OS_CRITICAL_EXIT();
  1941. *p_err = OS_ERR_SEM_OVF;
  1942. return ((OS_SEM_CTR)0);
  1943. }
  1944. break;
  1945. case 4u:
  1946. if (p_tcb->SemCtr == DEF_INT_32U_MAX_VAL) {
  1947. OS_CRITICAL_EXIT();
  1948. *p_err = OS_ERR_SEM_OVF;
  1949. return ((OS_SEM_CTR)0);
  1950. }
  1951. break;
  1952. default:
  1953. break;
  1954. }
  1955. p_tcb->SemCtr++; /* Task signaled is not pending on anything */
  1956. ctr = p_tcb->SemCtr;
  1957. OS_CRITICAL_EXIT();
  1958. break;
  1959. case OS_TASK_STATE_PEND:
  1960. case OS_TASK_STATE_PEND_TIMEOUT:
  1961. case OS_TASK_STATE_PEND_SUSPENDED:
  1962. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  1963. if (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_SEM) { /* Is task signaled waiting for a signal? */
  1964. OS_Post((OS_PEND_OBJ *)0, /* Task is pending on signal */
  1965. (OS_TCB *)p_tcb,
  1966. (void *)0,
  1967. (OS_MSG_SIZE )0u,
  1968. (CPU_TS )ts);
  1969. ctr = p_tcb->SemCtr;
  1970. OS_CRITICAL_EXIT_NO_SCHED();
  1971. if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
  1972. OSSched(); /* Run the scheduler */
  1973. }
  1974. } else {
  1975. p_tcb->SemCtr++; /* No, Task signaled is NOT pending on semaphore ... */
  1976. ctr = p_tcb->SemCtr; /* ... it must be waiting on something else */
  1977. OS_CRITICAL_EXIT();
  1978. }
  1979. break;
  1980. default:
  1981. OS_CRITICAL_EXIT();
  1982. *p_err = OS_ERR_STATE_INVALID;
  1983. ctr = (OS_SEM_CTR)0;
  1984. break;
  1985. }
  1986. return (ctr);
  1987. }