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