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

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

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_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) {
126 *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
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
165 OS_CRITICAL_ENTER();
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
184 OS_CRITICAL_EXIT_NO_SCHED();
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) {
254 case OS_TMR_STATE_RUNNING:
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) {
343 case OS_TMR_STATE_RUNNING:
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 */
456 case OS_TMR_STATE_COMPLETED:
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
536 CPU_CRITICAL_ENTER();
537 state = p_tmr->State;
538 switch (state) {
539 case OS_TMR_STATE_UNUSED:
540 case OS_TMR_STATE_STOPPED:
541 case OS_TMR_STATE_COMPLETED:
542 case OS_TMR_STATE_RUNNING:
543 *p_err = OS_ERR_NONE;
544 break;
545
546 default:
547 *p_err = OS_ERR_TMR_INVALID_STATE;
548 break;
549 }
550 CPU_CRITICAL_EXIT();
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) {
631 case OS_TMR_STATE_RUNNING:
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
644 case OS_OPT_TMR_CALLBACK_ARG:
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
837 if (OSCfg_TmrTaskStkSize < OSCfg_StkSizeMin) {
838 *p_err = OS_ERR_TMR_STK_SIZE_INVALID;
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,
851 (OS_PRIO )OSCfg_TmrTaskPrio,
852 (CPU_STK *)OSCfg_TmrTaskStkBasePtr,
853 (CPU_STK_SIZE)OSCfg_TmrTaskStkLimit,
854 (CPU_STK_SIZE)OSCfg_TmrTaskStkSize,
855 (OS_MSG_QTY )0,
856 (OS_TICK )0,
857 (void *)0,
858 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
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 */
1060 (OS_OPT )OS_OPT_PEND_BLOCKING,
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