LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_tmr.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 * TIMER MANAGEMENT
10 *
11 * File : OS_TMR.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_tmr__c = "$Id: $";
38 #endif
39 
40 
41 #if OS_CFG_TMR_EN > 0u
42 /*
43 ************************************************************************************************************************
44 * CONSTANTS
45 ************************************************************************************************************************
46 */
47 
48 #define OS_OPT_LINK_DLY (OS_OPT)(0u)
49 #define OS_OPT_LINK_PERIODIC (OS_OPT)(1u)
50 
51 /*$PAGE*/
52 /*
53 ************************************************************************************************************************
54 * CREATE A TIMER
55 *
56 * Description: This function is called by your application code to create a timer.
57 *
58 * Arguments : p_tmr Is a pointer to a timer control block
59 *
60 * p_name Is a pointer to an ASCII string that is used to name the timer. Names are useful for
61 * debugging.
62 *
63 * dly Initial delay.
64 * If the timer is configured for ONE-SHOT mode, this is the timeout used
65 * If the timer is configured for PERIODIC mode, this is the first timeout to wait for
66 * before the timer starts entering periodic mode
67 *
68 * period The 'period' being repeated for the timer.
69 * If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will
70 * automatically restart with the same period.
71 *
72 * opt Specifies either:
73 *
74 * OS_OPT_TMR_ONE_SHOT The timer counts down only once
75 * OS_OPT_TMR_PERIODIC The timer counts down and then reloads itself
76 *
77 * p_callback Is a pointer to a callback function that will be called when the timer expires. The
78 * callback function must be declared as follows:
79 *
80 * void MyCallback (OS_TMR *p_tmr, void *p_arg);
81 *
82 * p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
83 *
84 * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
85 *
86 * OS_ERR_NONE
87 * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the timer after you called
88 * OSSafetyCriticalStart().
89 * OS_ERR_OBJ_CREATED if the timer has already been created
90 * OS_ERR_OBJ_PTR_NULL is 'p_tmr' is a NULL pointer
91 * OS_ERR_OBJ_TYPE if the object type is invalid
92 * OS_ERR_OPT_INVALID you specified an invalid option
93 * OS_ERR_TMR_INVALID_DLY you specified an invalid delay
94 * OS_ERR_TMR_INVALID_PERIOD you specified an invalid period
95 * OS_ERR_TMR_ISR if the call was made from an ISR
96 *
97 * Returns : none
98 *
99 * Note(s) : 1) This function only creates the timer. In other words, the timer is not started when created. To
100 * start the timer, call OSTmrStart().
101 ************************************************************************************************************************
102 */
103 
104 void OSTmrCreate (OS_TMR *p_tmr,
105  CPU_CHAR *p_name,
106  OS_TICK dly,
107  OS_TICK period,
108  OS_OPT opt,
109  OS_TMR_CALLBACK_PTR p_callback,
110  void *p_callback_arg,
111  OS_ERR *p_err)
112 {
113  CPU_SR_ALLOC();
114 
115 
116 
117 #ifdef OS_SAFETY_CRITICAL
118  if (p_err == (OS_ERR *)0) {
119  OS_SAFETY_CRITICAL_EXCEPTION();
120  return;
121  }
122 #endif
123 
124 #ifdef OS_SAFETY_CRITICAL_IEC61508
125  if (OSSafetyCriticalStartFlag == DEF_TRUE) {
127  return;
128  }
129 #endif
130 
131 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
132  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
133  *p_err = OS_ERR_TMR_ISR;
134  return;
135  }
136 #endif
137 
138 #if OS_CFG_ARG_CHK_EN > 0u
139  if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */
140  *p_err = OS_ERR_OBJ_PTR_NULL;
141  return;
142  }
143 
144  switch (opt) {
145  case OS_OPT_TMR_PERIODIC:
146  if (period == (OS_TICK)0) {
147  *p_err = OS_ERR_TMR_INVALID_PERIOD;
148  return;
149  }
150  break;
151 
152  case OS_OPT_TMR_ONE_SHOT:
153  if (dly == (OS_TICK)0) {
154  *p_err = OS_ERR_TMR_INVALID_DLY;
155  return;
156  }
157  break;
158 
159  default:
160  *p_err = OS_ERR_OPT_INVALID;
161  return;
162  }
163 #endif
164 
166  p_tmr->State = (OS_STATE )OS_TMR_STATE_STOPPED; /* Initialize the timer fields */
167  p_tmr->Type = (OS_OBJ_TYPE )OS_OBJ_TYPE_TMR;
168  p_tmr->NamePtr = (CPU_CHAR *)p_name;
169  p_tmr->Dly = (OS_TICK )dly;
170  p_tmr->Match = (OS_TICK )0;
171  p_tmr->Remain = (OS_TICK )0;
172  p_tmr->Period = (OS_TICK )period;
173  p_tmr->Opt = (OS_OPT )opt;
174  p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)p_callback;
175  p_tmr->CallbackPtrArg = (void *)p_callback_arg;
176  p_tmr->NextPtr = (OS_TMR *)0;
177  p_tmr->PrevPtr = (OS_TMR *)0;
178 
179 #if OS_CFG_DBG_EN > 0u
180  OS_TmrDbgListAdd(p_tmr);
181 #endif
182  OSTmrQty++; /* Keep track of the number of timers created */
183 
185  *p_err = OS_ERR_NONE;
186 }
187 
188 /*$PAGE*/
189 /*
190 ************************************************************************************************************************
191 * DELETE A TIMER
192 *
193 * Description: This function is called by your application code to delete a timer.
194 *
195 * Arguments : p_tmr Is a pointer to the timer to stop and delete.
196 *
197 * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
198 *
199 * OS_ERR_NONE
200 * OS_ERR_OBJ_TYPE 'p_tmr' is not pointing to a timer
201 * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
202 * OS_ERR_TMR_ISR if the function was called from an ISR
203 * OS_ERR_TMR_INACTIVE if the timer was not created
204 * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
205 *
206 * Returns : DEF_TRUE if the timer was deleted
207 * DEF_FALSE if not or upon an error
208 ************************************************************************************************************************
209 */
210 
211 #if OS_CFG_TMR_DEL_EN > 0u
212 CPU_BOOLEAN OSTmrDel (OS_TMR *p_tmr,
213  OS_ERR *p_err)
214 {
215  OS_ERR err;
216 
217 
218 
219 #ifdef OS_SAFETY_CRITICAL
220  if (p_err == (OS_ERR *)0) {
221  OS_SAFETY_CRITICAL_EXCEPTION();
222  return (DEF_FALSE);
223  }
224 #endif
225 
226 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
227  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
228  *p_err = OS_ERR_TMR_ISR;
229  return (DEF_FALSE);
230  }
231 #endif
232 
233 #if OS_CFG_ARG_CHK_EN > 0u
234  if (p_tmr == (OS_TMR *)0) {
235  *p_err = OS_ERR_TMR_INVALID;
236  return (DEF_FALSE);
237  }
238 #endif
239 
240 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
241  if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
242  *p_err = OS_ERR_OBJ_TYPE;
243  return (DEF_FALSE);
244  }
245 #endif
246 
247  OSSchedLock(&err);
248 #if OS_CFG_DBG_EN > 0u
249  OS_TmrDbgListRemove(p_tmr);
250 #endif
251  OSTmrQty--; /* One less timer */
252 
253  switch (p_tmr->State) {
255  OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */
256  OS_TmrClr(p_tmr);
257  OSSchedUnlock(&err);
258  *p_err = OS_ERR_NONE;
259  return (DEF_TRUE);
260 
261  case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
262  case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
263  OS_TmrClr(p_tmr); /* Clear timer fields */
264  OSSchedUnlock(&err);
265  *p_err = OS_ERR_NONE;
266  return (DEF_TRUE);
267 
268  case OS_TMR_STATE_UNUSED: /* Already deleted */
269  OSSchedUnlock(&err);
270  *p_err = OS_ERR_TMR_INACTIVE;
271  return (DEF_FALSE);
272 
273  default:
274  OSSchedUnlock(&err);
275  *p_err = OS_ERR_TMR_INVALID_STATE;
276  return (DEF_FALSE);
277  }
278 }
279 #endif
280 
281 /*$PAGE*/
282 /*
283 ************************************************************************************************************************
284 * GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
285 *
286 * Description: This function is called to get the number of ticks before a timer times out.
287 *
288 * Arguments : p_tmr Is a pointer to the timer to obtain the remaining time from.
289 *
290 * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
291 *
292 * OS_ERR_NONE
293 * OS_ERR_OBJ_TYPE 'p_tmr' is not pointing to a timer
294 * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
295 * OS_ERR_TMR_ISR if the call was made from an ISR
296 * OS_ERR_TMR_INACTIVE 'p_tmr' points to a timer that is not active
297 * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
298 *
299 * Returns : The time remaining for the timer to expire. The time represents 'timer' increments. In other words, if
300 * OS_TmrTask() is signaled every 1/10 of a second then the returned value represents the number of 1/10 of
301 * a second remaining before the timer expires.
302 ************************************************************************************************************************
303 */
304 
305 OS_TICK OSTmrRemainGet (OS_TMR *p_tmr,
306  OS_ERR *p_err)
307 {
308  OS_TICK remain;
309  OS_ERR err;
310 
311 
312 
313 #ifdef OS_SAFETY_CRITICAL
314  if (p_err == (OS_ERR *)0) {
315  OS_SAFETY_CRITICAL_EXCEPTION();
316  return ((OS_TICK)0);
317  }
318 #endif
319 
320 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
321  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
322  *p_err = OS_ERR_TMR_ISR;
323  return ((OS_TICK)0);
324  }
325 #endif
326 
327 #if OS_CFG_ARG_CHK_EN > 0u
328  if (p_tmr == (OS_TMR *)0) {
329  *p_err = OS_ERR_TMR_INVALID;
330  return ((OS_TICK)0);
331  }
332 #endif
333 
334 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
335  if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
336  *p_err = OS_ERR_OBJ_TYPE;
337  return ((OS_TICK)0);
338  }
339 #endif
340 
341  OSSchedLock(&err);
342  switch (p_tmr->State) {
344  remain = p_tmr->Match /* Determine how much time is left to timeout */
345  - OSTmrTickCtr;
346  p_tmr->Remain = remain;
347  OSSchedUnlock(&err);
348  *p_err = OS_ERR_NONE;
349  return (remain);
350 
351  case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
352  if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
353  if (p_tmr->Dly == 0u) {
354  remain = p_tmr->Period;
355  } else {
356  remain = p_tmr->Dly;
357  }
358  } else {
359  remain = p_tmr->Dly;
360  }
361  p_tmr->Remain = remain;
362  OSSchedUnlock(&err);
363  *p_err = OS_ERR_NONE;
364  return (remain);
365 
366  case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT that timed out can be in this state */
367  OSSchedUnlock(&err);
368  *p_err = OS_ERR_NONE;
369  return ((OS_TICK)0);
370 
371  case OS_TMR_STATE_UNUSED:
372  OSSchedUnlock(&err);
373  *p_err = OS_ERR_TMR_INACTIVE;
374  return ((OS_TICK)0);
375 
376  default:
377  OSSchedUnlock(&err);
378  *p_err = OS_ERR_TMR_INVALID_STATE;
379  return ((OS_TICK)0);
380  }
381 }
382 
383 /*$PAGE*/
384 /*
385 ************************************************************************************************************************
386 * START A TIMER
387 *
388 * Description: This function is called by your application code to start a timer.
389 *
390 * Arguments : p_tmr Is a pointer to an OS_TMR
391 *
392 * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
393 *
394 * OS_ERR_NONE
395 * OS_ERR_OBJ_TYPE if 'p_tmr' is not pointing to a timer
396 * OS_ERR_TMR_INVALID
397 * OS_ERR_TMR_INACTIVE if the timer was not created
398 * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
399 * OS_ERR_TMR_ISR if the call was made from an ISR
400 *
401 * Returns : DEF_TRUE is the timer was started
402 * DEF_FALSE if not or upon an error
403 *
404 * Note(s) : 1) When starting/restarting a timer, regardless if it is in PERIODIC or ONE-SHOT mode, the timer is
405 * linked to the timer wheel with the OS_OPT_LINK_DLY option. This option sets the initial expiration
406 * time for the timer. For timers in PERIODIC mode, subsequent expiration times are handled by
407 * the OS_TmrTask().
408 ************************************************************************************************************************
409 */
410 
411 CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr,
412  OS_ERR *p_err)
413 {
414  OS_ERR err;
415 
416 
417 
418 #ifdef OS_SAFETY_CRITICAL
419  if (p_err == (OS_ERR *)0) {
420  OS_SAFETY_CRITICAL_EXCEPTION();
421  return (DEF_FALSE);
422  }
423 #endif
424 
425 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
426  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
427  *p_err = OS_ERR_TMR_ISR;
428  return (DEF_FALSE);
429  }
430 #endif
431 
432 #if OS_CFG_ARG_CHK_EN > 0u
433  if (p_tmr == (OS_TMR *)0) {
434  *p_err = OS_ERR_TMR_INVALID;
435  return (DEF_FALSE);
436  }
437 #endif
438 
439 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
440  if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
441  *p_err = OS_ERR_OBJ_TYPE;
442  return (DEF_FALSE);
443  }
444 #endif
445 
446  OSSchedLock(&err);
447  switch (p_tmr->State) {
448  case OS_TMR_STATE_RUNNING: /* Restart the timer */
449  OS_TmrUnlink(p_tmr); /* ... Stop the timer */
450  OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); /* ... Link timer to timer wheel (see Note #1). */
451  OSSchedUnlock(&err);
452  *p_err = OS_ERR_NONE;
453  return (DEF_TRUE);
454 
455  case OS_TMR_STATE_STOPPED: /* Start the timer */
457  OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); /* ... Link timer to timer wheel (see Note #1). */
458  OSSchedUnlock(&err);
459  *p_err = OS_ERR_NONE;
460  return (DEF_TRUE);
461 
462  case OS_TMR_STATE_UNUSED: /* Timer not created */
463  OSSchedUnlock(&err);
464  *p_err = OS_ERR_TMR_INACTIVE;
465  return (DEF_FALSE);
466 
467  default:
468  OSSchedUnlock(&err);
469  *p_err = OS_ERR_TMR_INVALID_STATE;
470  return (DEF_FALSE);
471  }
472 }
473 
474 /*$PAGE*/
475 /*
476 ************************************************************************************************************************
477 * FIND OUT WHAT STATE A TIMER IS IN
478 *
479 * Description: This function is called to determine what state the timer is in:
480 *
481 * OS_TMR_STATE_UNUSED the timer has not been created
482 * OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped
483 * OS_TMR_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout
484 * OS_TMR_RUNNING the timer is currently running
485 *
486 * Arguments : p_tmr Is a pointer to the desired timer
487 *
488 * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
489 *
490 * OS_ERR_NONE
491 * OS_ERR_OBJ_TYPE if 'p_tmr' is not pointing to a timer
492 * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
493 * OS_ERR_TMR_INVALID_STATE if the timer is not in a valid state
494 * OS_ERR_TMR_ISR if the call was made from an ISR
495 *
496 * Returns : The current state of the timer (see description).
497 ************************************************************************************************************************
498 */
499 
500 OS_STATE OSTmrStateGet (OS_TMR *p_tmr,
501  OS_ERR *p_err)
502 {
503  OS_STATE state;
504  CPU_SR_ALLOC();
505 
506 
507 
508 #ifdef OS_SAFETY_CRITICAL
509  if (p_err == (OS_ERR *)0) {
510  OS_SAFETY_CRITICAL_EXCEPTION();
511  return (OS_TMR_STATE_UNUSED);
512  }
513 #endif
514 
515 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
516  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
517  *p_err = OS_ERR_TMR_ISR;
518  return (OS_TMR_STATE_UNUSED);
519  }
520 #endif
521 
522 #if OS_CFG_ARG_CHK_EN > 0u
523  if (p_tmr == (OS_TMR *)0) {
524  *p_err = OS_ERR_TMR_INVALID;
525  return (OS_TMR_STATE_UNUSED);
526  }
527 #endif
528 
529 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
530  if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
531  *p_err = OS_ERR_OBJ_TYPE;
532  return (OS_TMR_STATE_UNUSED);
533  }
534 #endif
535 
537  state = p_tmr->State;
538  switch (state) {
539  case OS_TMR_STATE_UNUSED:
543  *p_err = OS_ERR_NONE;
544  break;
545 
546  default:
547  *p_err = OS_ERR_TMR_INVALID_STATE;
548  break;
549  }
551  return (state);
552 }
553 
554 /*$PAGE*/
555 /*
556 ************************************************************************************************************************
557 * STOP A TIMER
558 *
559 * Description: This function is called by your application code to stop a timer.
560 *
561 * Arguments : p_tmr Is a pointer to the timer to stop.
562 *
563 * opt Allows you to specify an option to this functions which can be:
564 *
565 * OS_OPT_TMR_NONE Do nothing special but stop the timer
566 * OS_OPT_TMR_CALLBACK Execute the callback function, pass it the callback argument
567 * specified when the timer was created.
568 * OS_OPT_TMR_CALLBACK_ARG Execute the callback function, pass it the callback argument
569 * specified in THIS function call
570 *
571 * callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function
572 * instead of the timer's callback argument. In other words, use 'callback_arg' passed in
573 * THIS function INSTEAD of p_tmr->OSTmrCallbackArg
574 *
575 * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
576 * OS_ERR_NONE
577 * OS_ERR_OBJ_TYPE if 'p_tmr' is not pointing to a timer
578 * OS_ERR_OPT_INVALID if you specified an invalid option for 'opt'
579 * OS_ERR_TMR_INACTIVE if the timer was not created
580 * OS_ERR_TMR_INVALID 'p_tmr' is a NULL pointer
581 * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
582 * OS_ERR_TMR_ISR if the function was called from an ISR
583 * OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined
584 * OS_ERR_TMR_STOPPED if the timer was already stopped
585 *
586 * Returns : DEF_TRUE If we stopped the timer (if the timer is already stopped, we also return DEF_TRUE)
587 * DEF_FALSE If not
588 ************************************************************************************************************************
589 */
590 
591 CPU_BOOLEAN OSTmrStop (OS_TMR *p_tmr,
592  OS_OPT opt,
593  void *p_callback_arg,
594  OS_ERR *p_err)
595 {
596  OS_TMR_CALLBACK_PTR p_fnct;
597  OS_ERR err;
598 
599 
600 
601 #ifdef OS_SAFETY_CRITICAL
602  if (p_err == (OS_ERR *)0) {
603  OS_SAFETY_CRITICAL_EXCEPTION();
604  return (DEF_FALSE);
605  }
606 #endif
607 
608 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
609  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to call from an ISR */
610  *p_err = OS_ERR_TMR_ISR;
611  return (DEF_FALSE);
612  }
613 #endif
614 
615 #if OS_CFG_ARG_CHK_EN > 0u
616  if (p_tmr == (OS_TMR *)0) {
617  *p_err = OS_ERR_TMR_INVALID;
618  return (DEF_FALSE);
619  }
620 #endif
621 
622 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
623  if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
624  *p_err = OS_ERR_OBJ_TYPE;
625  return (DEF_FALSE);
626  }
627 #endif
628 
629  OSSchedLock(&err);
630  switch (p_tmr->State) {
632  OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */
633  *p_err = OS_ERR_NONE;
634  switch (opt) {
635  case OS_OPT_TMR_CALLBACK:
636  p_fnct = p_tmr->CallbackPtr; /* Execute callback function ... */
637  if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { /* ... if available */
638  (*p_fnct)((void *)p_tmr, p_tmr->CallbackPtrArg); /* Use callback arg when timer was created */
639  } else {
640  *p_err = OS_ERR_TMR_NO_CALLBACK;
641  }
642  break;
643 
645  p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available ... */
646  if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
647  (*p_fnct)((void *)p_tmr, p_callback_arg); /* .. using the 'callback_arg' provided in call */
648  } else {
649  *p_err = OS_ERR_TMR_NO_CALLBACK;
650  }
651  break;
652 
653  case OS_OPT_TMR_NONE:
654  break;
655 
656  default:
657  OSSchedUnlock(&err);
658  *p_err = OS_ERR_OPT_INVALID;
659  return (DEF_FALSE);
660  }
661  OSSchedUnlock(&err);
662  return (DEF_TRUE);
663 
664  case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or */
665  case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
666  OSSchedUnlock(&err);
667  *p_err = OS_ERR_TMR_STOPPED;
668  return (DEF_TRUE);
669 
670  case OS_TMR_STATE_UNUSED: /* Timer was not created */
671  OSSchedUnlock(&err);
672  *p_err = OS_ERR_TMR_INACTIVE;
673  return (DEF_FALSE);
674 
675  default:
676  OSSchedUnlock(&err);
677  *p_err = OS_ERR_TMR_INVALID_STATE;
678  return (DEF_FALSE);
679  }
680 }
681 
682 /*$PAGE*/
683 /*
684 ************************************************************************************************************************
685 * CLEAR TIMER FIELDS
686 *
687 * Description: This function is called to clear all timer fields.
688 *
689 * Argument(s): p_tmr is a pointer to the timer to clear
690 * -----
691 *
692 * Returns : none
693 *
694 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
695 ************************************************************************************************************************
696 */
697 
698 void OS_TmrClr (OS_TMR *p_tmr)
699 {
700  p_tmr->State = OS_TMR_STATE_UNUSED; /* Clear timer fields */
701  p_tmr->Type = OS_OBJ_TYPE_NONE;
702  p_tmr->NamePtr = (CPU_CHAR *)((void *)"?TMR");
703  p_tmr->Dly = (OS_TICK )0;
704  p_tmr->Match = (OS_TICK )0;
705  p_tmr->Remain = (OS_TICK )0;
706  p_tmr->Period = (OS_TICK )0;
707  p_tmr->Opt = (OS_OPT )0;
708  p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)0;
709  p_tmr->CallbackPtrArg = (void *)0;
710  p_tmr->NextPtr = (OS_TMR *)0;
711  p_tmr->PrevPtr = (OS_TMR *)0;
712 }
713 
714 /*$PAGE*/
715 /*
716 ************************************************************************************************************************
717 * ADD/REMOVE TIMER TO/FROM DEBUG TABLE
718 *
719 * Description: These functions are called by uC/OS-III to add or remove a timer to/from a timer debug table.
720 *
721 * Arguments : p_tmr is a pointer to the timer to add/remove
722 *
723 * Returns : none
724 *
725 * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
726 ************************************************************************************************************************
727 */
728 
729 
730 #if OS_CFG_DBG_EN > 0u
731 void OS_TmrDbgListAdd (OS_TMR *p_tmr)
732 {
733  p_tmr->DbgPrevPtr = (OS_TMR *)0;
734  if (OSTmrDbgListPtr == (OS_TMR *)0) {
735  p_tmr->DbgNextPtr = (OS_TMR *)0;
736  } else {
737  p_tmr->DbgNextPtr = OSTmrDbgListPtr;
738  OSTmrDbgListPtr->DbgPrevPtr = p_tmr;
739  }
740  OSTmrDbgListPtr = p_tmr;
741 }
742 
743 
744 
745 void OS_TmrDbgListRemove (OS_TMR *p_tmr)
746 {
747  OS_TMR *p_tmr_next;
748  OS_TMR *p_tmr_prev;
749 
750 
751  p_tmr_prev = p_tmr->DbgPrevPtr;
752  p_tmr_next = p_tmr->DbgNextPtr;
753 
754  if (p_tmr_prev == (OS_TMR *)0) {
755  OSTmrDbgListPtr = p_tmr_next;
756  if (p_tmr_next != (OS_TMR *)0) {
757  p_tmr_next->DbgPrevPtr = (OS_TMR *)0;
758  }
759  p_tmr->DbgNextPtr = (OS_TMR *)0;
760 
761  } else if (p_tmr_next == (OS_TMR *)0) {
762  p_tmr_prev->DbgNextPtr = (OS_TMR *)0;
763  p_tmr->DbgPrevPtr = (OS_TMR *)0;
764 
765  } else {
766  p_tmr_prev->DbgNextPtr = p_tmr_next;
767  p_tmr_next->DbgPrevPtr = p_tmr_prev;
768  p_tmr->DbgNextPtr = (OS_TMR *)0;
769  p_tmr->DbgPrevPtr = (OS_TMR *)0;
770  }
771 }
772 #endif
773 
774 /*$PAGE*/
775 /*
776 ************************************************************************************************************************
777 * INITIALIZE THE TIMER MANAGER
778 *
779 * Description: This function is called by OSInit() to initialize the timer manager module.
780 *
781 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
782 *
783 * OS_ERR_NONE
784 * OS_ERR_TMR_STK_INVALID if you didn't specify a stack for the timer task
785 * OS_ERR_TMR_STK_SIZE_INVALID if you didn't allocate enough space for the timer stack
786 * OS_ERR_PRIO_INVALID if you specified the same priority as the idle task
787 * OS_ERR_xxx any error code returned by OSTaskCreate()
788 *
789 * Returns : none
790 *
791 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
792 ************************************************************************************************************************
793 */
794 
795 void OS_TmrInit (OS_ERR *p_err)
796 {
797  OS_TMR_SPOKE_IX i;
798  OS_TMR_SPOKE *p_spoke;
799 
800 
801 
802 #ifdef OS_SAFETY_CRITICAL
803  if (p_err == (OS_ERR *)0) {
804  OS_SAFETY_CRITICAL_EXCEPTION();
805  return;
806  }
807 #endif
808 
809 #if OS_CFG_DBG_EN > 0u
810  OSTmrDbgListPtr = (OS_TMR *)0;
811 #endif
812 
813  if (OSCfg_TmrTaskRate_Hz > (OS_RATE_HZ)0) {
814  OSTmrUpdateCnt = OSCfg_TickRate_Hz / OSCfg_TmrTaskRate_Hz;
815  } else {
816  OSTmrUpdateCnt = OSCfg_TickRate_Hz / (OS_RATE_HZ)10;
817  }
818  OSTmrUpdateCtr = OSTmrUpdateCnt;
819 
820  OSTmrTickCtr = (OS_TICK)0;
821 
822  OSTmrTaskTimeMax = (CPU_TS)0;
823 
824  for (i = 0u; i < OSCfg_TmrWheelSize; i++) {
825  p_spoke = &OSCfg_TmrWheel[i];
826  p_spoke->NbrEntries = (OS_OBJ_QTY)0;
827  p_spoke->NbrEntriesMax = (OS_OBJ_QTY)0;
828  p_spoke->FirstPtr = (OS_TMR *)0;
829  }
830 
831  /* ---------------- CREATE THE TIMER TASK --------------- */
832  if (OSCfg_TmrTaskStkBasePtr == (CPU_STK*)0) {
833  *p_err = OS_ERR_TMR_STK_INVALID;
834  return;
835  }
836 
839  return;
840  }
841 
842  if (OSCfg_TmrTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) {
843  *p_err = OS_ERR_TMR_PRIO_INVALID;
844  return;
845  }
846 
847  OSTaskCreate((OS_TCB *)&OSTmrTaskTCB,
848  (CPU_CHAR *)((void *)"uC/OS-III Timer Task"),
849  (OS_TASK_PTR )OS_TmrTask,
850  (void *)0,
855  (OS_MSG_QTY )0,
856  (OS_TICK )0,
857  (void *)0,
859  (OS_ERR *)p_err);
860 }
861 
862 /*$PAGE*/
863 /*
864 ************************************************************************************************************************
865 * INSERT A TIMER INTO THE TIMER WHEEL
866 *
867 * Description: This function is called to insert the timer into the timer wheel. The timer is always inserted at the
868 * beginning of the list.
869 *
870 * Arguments : p_tmr Is a pointer to the timer to insert.
871 * -----
872 *
873 * opt Is either:
874 *
875 * OS_OPT_LINK_PERIODIC Means to re-insert the timer after a period expired
876 * OS_OPT_LINK_DLY Means to insert the timer the first time
877 *
878 * Returns : none
879 *
880 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
881 ************************************************************************************************************************
882 */
883 
884 void OS_TmrLink (OS_TMR *p_tmr,
885  OS_OPT opt)
886 {
887  OS_TMR_SPOKE *p_spoke;
888  OS_TMR *p_tmr0;
889  OS_TMR *p_tmr1;
890  OS_TMR_SPOKE_IX spoke;
891 
892 
893 
894  p_tmr->State = OS_TMR_STATE_RUNNING;
895  if (opt == OS_OPT_LINK_PERIODIC) { /* Determine when timer will expire */
896  p_tmr->Match = p_tmr->Period + OSTmrTickCtr;
897  } else {
898  if (p_tmr->Dly == (OS_TICK)0) {
899  p_tmr->Match = p_tmr->Period + OSTmrTickCtr;
900  } else {
901  p_tmr->Match = p_tmr->Dly + OSTmrTickCtr;
902  }
903  }
904  spoke = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize);
905  p_spoke = &OSCfg_TmrWheel[spoke];
906 
907  if (p_spoke->FirstPtr == (OS_TMR *)0) { /* Link into timer wheel */
908  p_tmr->NextPtr = (OS_TMR *)0;
909  p_tmr->PrevPtr = (OS_TMR *)0;
910  p_spoke->FirstPtr = p_tmr;
911  p_spoke->NbrEntries = 1u;
912  } else {
913  p_tmr->Remain = p_tmr->Match /* Compute remaining time for timer */
914  - OSTmrTickCtr;
915  p_tmr1 = p_spoke->FirstPtr; /* Point to current first timer in the list */
916  while (p_tmr1 != (OS_TMR *)0) {
917  p_tmr1->Remain = p_tmr1->Match /* Compute time remaining of current timer in list */
918  - OSTmrTickCtr;
919  if (p_tmr->Remain > p_tmr1->Remain) { /* Do we need to insert AFTER current timer in list? */
920  if (p_tmr1->NextPtr != (OS_TMR *)0) { /* Yes, are we pointing at the last timer in the list? */
921  p_tmr1 = p_tmr1->NextPtr; /* No, Point to next timer in the list */
922  } else {
923  p_tmr->NextPtr = (OS_TMR *)0;
924  p_tmr->PrevPtr = p_tmr1;
925  p_tmr1->NextPtr = p_tmr; /* Yes, timer to insert is now new last entry in the list */
926  p_tmr1 = (OS_TMR *)0; /* Break loop */
927  }
928  } else { /* Insert before the current timer */
929  if (p_tmr1->PrevPtr == (OS_TMR *)0) { /* Are we inserting before the first timer? */
930  p_tmr->PrevPtr = (OS_TMR *)0;
931  p_tmr->NextPtr = p_tmr1;
932  p_tmr1->PrevPtr = p_tmr;
933  p_spoke->FirstPtr = p_tmr;
934  } else { /* Insert in between 2 timers already in the list */
935  p_tmr0 = p_tmr1->PrevPtr;
936  p_tmr->PrevPtr = p_tmr0;
937  p_tmr->NextPtr = p_tmr1;
938  p_tmr0->NextPtr = p_tmr;
939  p_tmr1->PrevPtr = p_tmr;
940  }
941  p_tmr1 = (OS_TMR *)0; /* Break loop */
942  }
943  }
944  p_spoke->NbrEntries++;
945  }
946  if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) { /* Keep track of maximum number of entries in each spoke */
947  p_spoke->NbrEntriesMax = p_spoke->NbrEntries;
948  }
949 }
950 
951 /*$PAGE*/
952 /*
953 ************************************************************************************************************************
954 * RESET TIMER LIST PEAK DETECTOR
955 *
956 * Description: This function is used to reset the peak detector for the number of entries in each spoke.
957 *
958 * Arguments : void
959 *
960 * Returns : none
961 *
962 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
963 ************************************************************************************************************************
964 */
965 
966 void OS_TmrResetPeak (void)
967 {
968  OS_TMR_SPOKE *p_spoke;
969  OS_TMR_SPOKE_IX i;
970 
971 
972 
973  for (i = 0u; i < OSCfg_TmrWheelSize; i++) {
974  p_spoke = (OS_TMR_SPOKE *)&OSCfg_TmrWheel[i];
975  p_spoke->NbrEntriesMax = (OS_OBJ_QTY )0u;
976  }
977 }
978 
979 /*$PAGE*/
980 /*
981 ************************************************************************************************************************
982 * REMOVE A TIMER FROM THE TIMER WHEEL
983 *
984 * Description: This function is called to remove the timer from the timer wheel.
985 *
986 * Arguments : p_tmr Is a pointer to the timer to remove.
987 * -----
988 *
989 * Returns : none
990 *
991 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
992 ************************************************************************************************************************
993 */
994 
995 void OS_TmrUnlink (OS_TMR *p_tmr)
996 {
997  OS_TMR_SPOKE *p_spoke;
998  OS_TMR *p_tmr1;
999  OS_TMR *p_tmr2;
1000  OS_TMR_SPOKE_IX spoke;
1001 
1002 
1003 
1004  spoke = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize);
1005  p_spoke = &OSCfg_TmrWheel[spoke];
1006 
1007  if (p_spoke->FirstPtr == p_tmr) { /* See if timer to remove is at the beginning of list */
1008  p_tmr1 = (OS_TMR *)p_tmr->NextPtr;
1009  p_spoke->FirstPtr = (OS_TMR *)p_tmr1;
1010  if (p_tmr1 != (OS_TMR *)0) {
1011  p_tmr1->PrevPtr = (OS_TMR *)0;
1012  }
1013  } else {
1014  p_tmr1 = (OS_TMR *)p_tmr->PrevPtr; /* Remove timer from somewhere in the list */
1015  p_tmr2 = (OS_TMR *)p_tmr->NextPtr;
1016  p_tmr1->NextPtr = p_tmr2;
1017  if (p_tmr2 != (OS_TMR *)0) {
1018  p_tmr2->PrevPtr = (OS_TMR *)p_tmr1;
1019  }
1020  }
1021  p_tmr->State = OS_TMR_STATE_STOPPED;
1022  p_tmr->NextPtr = (OS_TMR *)0;
1023  p_tmr->PrevPtr = (OS_TMR *)0;
1024  p_spoke->NbrEntries--;
1025 }
1026 
1027 /*$PAGE*/
1028 /*
1029 ************************************************************************************************************************
1030 * TIMER MANAGEMENT TASK
1031 *
1032 * Description: This task is created by OS_TmrInit().
1033 *
1034 * Arguments : none
1035 *
1036 * Returns : none
1037 *
1038 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1039 ************************************************************************************************************************
1040 */
1041 
1042 void OS_TmrTask (void *p_arg)
1043 {
1044  CPU_BOOLEAN done;
1045  OS_ERR err;
1046  OS_TMR_CALLBACK_PTR p_fnct;
1047  OS_TMR_SPOKE *p_spoke;
1048  OS_TMR *p_tmr;
1049  OS_TMR *p_tmr_next;
1050  OS_TMR_SPOKE_IX spoke;
1051  CPU_TS ts;
1052  CPU_TS ts_start;
1053  CPU_TS ts_end;
1054 
1055 
1056 
1057  p_arg = p_arg; /* Not using 'p_arg', prevent compiler warning */
1058  while (DEF_ON) {
1059  (void)OSTaskSemPend((OS_TICK )0, /* Wait for signal indicating time to update tmrs */
1061  (CPU_TS *)&ts,
1062  (OS_ERR *)&err);
1063 
1064  OSSchedLock(&err);
1065  ts_start = OS_TS_GET();
1066  OSTmrTickCtr++; /* Increment the current time */
1067  spoke = (OS_TMR_SPOKE_IX)(OSTmrTickCtr % OSCfg_TmrWheelSize);
1068  p_spoke = &OSCfg_TmrWheel[spoke];
1069  p_tmr = p_spoke->FirstPtr;
1070  done = DEF_FALSE;
1071  while (done == DEF_FALSE) {
1072  if (p_tmr != (OS_TMR *)0) {
1073  p_tmr_next = (OS_TMR *)p_tmr->NextPtr; /* Point to next tmr to update because current ... */
1074  /* ... timer could get unlinked from the wheel. */
1075  if (OSTmrTickCtr == p_tmr->Match) { /* Process each timer that expires */
1076  OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */
1077  if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
1078  OS_TmrLink(p_tmr,
1079  OS_OPT_LINK_PERIODIC); /* Recalculate new position of timer in wheel */
1080  } else {
1081  p_tmr->State = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */
1082  }
1083  p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available */
1084  if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
1085  (*p_fnct)((void *)p_tmr,
1086  p_tmr->CallbackPtrArg);
1087  }
1088  p_tmr = p_tmr_next; /* See if next timer matches */
1089  } else {
1090  done = DEF_TRUE;
1091  }
1092  } else {
1093  done = DEF_TRUE;
1094  }
1095  }
1096  ts_end = OS_TS_GET() - ts_start; /* Measure execution time of timer task */
1097  OSSchedUnlock(&err);
1098  if (OSTmrTaskTimeMax < ts_end) {
1099  OSTmrTaskTimeMax = ts_end;
1100  }
1101  }
1102 }
1103 
1104 #endif