| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

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