os_tmr.c
上传用户:yj_qqy
上传日期:2017-01-28
资源大小:2911k
文件大小:44k
源码类别:

uCOS

开发平台:

C/C++

  1. /*
  2. ************************************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                            TIMER MANAGEMENT
  6. *
  7. *                              (c) Copyright 1992-2009, Micrium, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. *
  11. * File    : OS_TMR.C
  12. * By      : Jean J. Labrosse
  13. * Version : V2.88
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. *   uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.  
  18. * If you plan on using  uC/OS-II  in a commercial product you need to contact Micri祄 to properly license 
  19. * its use in your product. We provide ALL the source code for your convenience and to help you experience 
  20. * uC/OS-II.   The fact that the  source is provided does  NOT  mean that you can use it without  paying a 
  21. * licensing fee.
  22. ************************************************************************************************************************
  23. */
  24. #include <ucos_ii.h>
  25. /*
  26. ************************************************************************************************************************
  27. *                                                        NOTES
  28. *
  29. * 1) Your application MUST define the following #define constants:
  30. *
  31. *    OS_TASK_TMR_PRIO          The priority of the Timer management task
  32. *    OS_TASK_TMR_STK_SIZE      The size     of the Timer management task's stack
  33. *
  34. * 2) You must call OSTmrSignal() to notify the Timer management task that it's time to update the timers.
  35. ************************************************************************************************************************
  36. */
  37. /*
  38. ************************************************************************************************************************
  39. *                                                     CONSTANTS
  40. ************************************************************************************************************************
  41. */
  42. #define  OS_TMR_LINK_DLY       0
  43. #define  OS_TMR_LINK_PERIODIC  1
  44. /*
  45. ************************************************************************************************************************
  46. *                                                  LOCAL PROTOTYPES
  47. ************************************************************************************************************************
  48. */
  49. #if OS_TMR_EN > 0
  50. static  OS_TMR  *OSTmr_Alloc         (void);
  51. static  void     OSTmr_Free          (OS_TMR *ptmr);
  52. static  void     OSTmr_InitTask      (void);
  53. static  void     OSTmr_Link          (OS_TMR *ptmr, INT8U type);
  54. static  void     OSTmr_Unlink        (OS_TMR *ptmr);
  55. static  void     OSTmr_Task          (void   *p_arg);
  56. #endif
  57. /*$PAGE*/
  58. /*
  59. ************************************************************************************************************************
  60. *                                                   CREATE A TIMER
  61. *
  62. * Description: This function is called by your application code to create a timer.
  63. *
  64. * Arguments  : dly           Initial delay.
  65. *                            If the timer is configured for ONE-SHOT mode, this is the timeout used
  66. *                            If the timer is configured for PERIODIC mode, this is the first timeout to wait for
  67. *                               before the timer starts entering periodic mode
  68. *
  69. *              period        The 'period' being repeated for the timer.
  70. *                               If you specified 'OS_TMR_OPT_PERIODIC' as an option, when the timer expires, it will
  71. *                               automatically restart with the same period.
  72. *
  73. *              opt           Specifies either:
  74. *                               OS_TMR_OPT_ONE_SHOT       The timer counts down only once
  75. *                               OS_TMR_OPT_PERIODIC       The timer counts down and then reloads itself
  76. *
  77. *              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 *ptmr, void *p_arg);
  81. *
  82. *              callback_arg  Is an argument (a pointer) that is passed to the callback function when it is called.
  83. *
  84. *              pname         Is a pointer to an ASCII string that is used to name the timer.  Names are useful for
  85. *                               debugging.
  86. *
  87. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  88. *                               OS_ERR_NONE
  89. *                               OS_ERR_TMR_INVALID_DLY     you specified an invalid delay
  90. *                               OS_ERR_TMR_INVALID_PERIOD  you specified an invalid period
  91. *                               OS_ERR_TMR_INVALID_OPT     you specified an invalid option
  92. *                               OS_ERR_TMR_ISR             if the call was made from an ISR
  93. *                               OS_ERR_TMR_NON_AVAIL       if there are no free timers from the timer pool
  94. *
  95. * Returns    : A pointer to an OS_TMR data structure.  
  96. *              This is the 'handle' that your application will use to reference the timer created.
  97. ************************************************************************************************************************
  98. */
  99. #if OS_TMR_EN > 0
  100. OS_TMR  *OSTmrCreate (INT32U           dly,
  101.                       INT32U           period,
  102.                       INT8U            opt,
  103.                       OS_TMR_CALLBACK  callback,
  104.                       void            *callback_arg,
  105.                       INT8U           *pname,
  106.                       INT8U           *perr)
  107. {
  108.     OS_TMR   *ptmr;
  109. #if OS_ARG_CHK_EN > 0
  110.     if (perr == (INT8U *)0) {                               /* Validate arguments                                     */
  111.         return ((OS_TMR *)0);
  112.     }
  113.     switch (opt) {
  114.         case OS_TMR_OPT_PERIODIC:
  115.              if (period == 0) {
  116.                  *perr = OS_ERR_TMR_INVALID_PERIOD;
  117.                  return ((OS_TMR *)0);
  118.              }
  119.              break;
  120.         case OS_TMR_OPT_ONE_SHOT:
  121.              if (dly == 0) {
  122.                  *perr = OS_ERR_TMR_INVALID_DLY;
  123.                  return ((OS_TMR *)0);
  124.              }
  125.              break;
  126.         default:
  127.              *perr = OS_ERR_TMR_INVALID_OPT;
  128.              return ((OS_TMR *)0);
  129.     }
  130. #endif
  131.     if (OSIntNesting > 0) {                                 /* See if trying to call from an ISR                      */
  132.         *perr  = OS_ERR_TMR_ISR;
  133.         return ((OS_TMR *)0);
  134.     }
  135.     OSSchedLock();
  136.     ptmr = OSTmr_Alloc();                                   /* Obtain a timer from the free pool                      */
  137.     if (ptmr == (OS_TMR *)0) {
  138.         OSSchedUnlock();
  139.         *perr = OS_ERR_TMR_NON_AVAIL;
  140.         return ((OS_TMR *)0);
  141.     }
  142.     ptmr->OSTmrState       = OS_TMR_STATE_STOPPED;          /* Indicate that timer is not running yet                 */
  143.     ptmr->OSTmrDly         = dly;
  144.     ptmr->OSTmrPeriod      = period;
  145.     ptmr->OSTmrOpt         = opt;
  146.     ptmr->OSTmrCallback    = callback;
  147.     ptmr->OSTmrCallbackArg = callback_arg;
  148. #if OS_TMR_CFG_NAME_EN > 0
  149.     ptmr->OSTmrName        = pname;
  150. #endif
  151.     OSSchedUnlock();
  152.     *perr = OS_ERR_NONE;
  153.     return (ptmr);
  154. }
  155. #endif
  156. /*$PAGE*/
  157. /*
  158. ************************************************************************************************************************
  159. *                                                   DELETE A TIMER
  160. *
  161. * Description: This function is called by your application code to delete a timer.
  162. *
  163. * Arguments  : ptmr          Is a pointer to the timer to stop and delete.
  164. *
  165. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  166. *                               OS_ERR_NONE
  167. *                               OS_ERR_TMR_INVALID        'ptmr'  is a NULL pointer
  168. *                               OS_ERR_TMR_INVALID_TYPE   'ptmr'  is not pointing to an OS_TMR
  169. *                               OS_ERR_TMR_ISR            if the function was called from an ISR
  170. *                               OS_ERR_TMR_INACTIVE       if the timer was not created
  171. *                               OS_ERR_TMR_INVALID_STATE  the timer is in an invalid state
  172. *
  173. * Returns    : OS_TRUE       If the call was successful
  174. *              OS_FALSE      If not
  175. ************************************************************************************************************************
  176. */
  177. #if OS_TMR_EN > 0
  178. BOOLEAN  OSTmrDel (OS_TMR  *ptmr,
  179.                    INT8U   *perr)
  180. {
  181. #if OS_ARG_CHK_EN > 0
  182.     if (perr == (INT8U *)0) {                               /* Validate arguments                                     */
  183.         return (OS_FALSE);
  184.     }
  185.     if (ptmr == (OS_TMR *)0) {
  186.         *perr = OS_ERR_TMR_INVALID;
  187.         return (OS_FALSE);
  188.     }
  189. #endif
  190.     if (ptmr->OSTmrType != OS_TMR_TYPE) {                   /* Validate timer structure                               */
  191.         *perr = OS_ERR_TMR_INVALID_TYPE;
  192.         return (OS_FALSE);
  193.     }
  194.     if (OSIntNesting > 0) {                                 /* See if trying to call from an ISR                      */
  195.         *perr  = OS_ERR_TMR_ISR;
  196.         return (OS_FALSE);
  197.     }
  198.     OSSchedLock();
  199.     switch (ptmr->OSTmrState) {
  200.         case OS_TMR_STATE_RUNNING:
  201.              OSTmr_Unlink(ptmr);                            /* Remove from current wheel spoke                        */
  202.              OSTmr_Free(ptmr);                              /* Return timer to free list of timers                    */
  203.              OSSchedUnlock();
  204.              *perr = OS_ERR_NONE;
  205.              return (OS_TRUE);
  206.         case OS_TMR_STATE_STOPPED:                          /* Timer has not started or ...                           */
  207.         case OS_TMR_STATE_COMPLETED:                        /* ... timer has completed the ONE-SHOT time              */
  208.              OSTmr_Free(ptmr);                              /* Return timer to free list of timers                    */
  209.              OSSchedUnlock();
  210.              *perr = OS_ERR_NONE;
  211.              return (OS_TRUE);
  212.         case OS_TMR_STATE_UNUSED:                           /* Already deleted                                        */
  213.              OSSchedUnlock();
  214.              *perr = OS_ERR_TMR_INACTIVE;
  215.              return (OS_FALSE);
  216.         default:
  217.              OSSchedUnlock();
  218.              *perr = OS_ERR_TMR_INVALID_STATE;
  219.              return (OS_FALSE);
  220.     }
  221. }
  222. #endif
  223. /*$PAGE*/
  224. /*
  225. ************************************************************************************************************************
  226. *                                             GET THE NAME OF A TIMER
  227. *
  228. * Description: This function is called to obtain the name of a timer.
  229. *
  230. * Arguments  : ptmr          Is a pointer to the timer to obtain the name for
  231. *
  232. *              pdest         Is a pointer to where the name of the timer will be placed.  
  233. *
  234. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  235. *                               OS_ERR_NONE               The call was successful
  236. *                               OS_ERR_TMR_INVALID_DEST   'pdest' is a NULL pointer
  237. *                               OS_ERR_TMR_INVALID        'ptmr'  is a NULL pointer
  238. *                               OS_ERR_TMR_INVALID_TYPE   'ptmr'  is not pointing to an OS_TMR
  239. *                               OS_ERR_NAME_GET_ISR       if the call was made from an ISR
  240. *                               OS_ERR_TMR_INACTIVE       'ptmr'  points to a timer that is not active
  241. *                               OS_ERR_TMR_INVALID_STATE  the timer is in an invalid state
  242. *
  243. * Returns    : The length of the string or 0 if the timer does not exist.
  244. ************************************************************************************************************************
  245. */
  246. #if OS_TMR_EN > 0 && OS_TMR_CFG_NAME_EN > 0
  247. INT8U  OSTmrNameGet (OS_TMR  *ptmr,
  248.                      INT8U   *pdest,
  249.                      INT8U   *perr)
  250. {
  251.     INT8U  len;
  252. #if OS_ARG_CHK_EN > 0
  253.     if (perr == (INT8U *)0) {
  254.         return (0);
  255.     }
  256.     if (pdest == (INT8U *)0) {
  257.         *perr = OS_ERR_TMR_INVALID_DEST;
  258.         return (0);
  259.     }
  260.     if (ptmr == (OS_TMR *)0) {
  261.         *perr = OS_ERR_TMR_INVALID;
  262.         return (0);
  263.     }
  264. #endif
  265.     if (ptmr->OSTmrType != OS_TMR_TYPE) {              /* Validate timer structure                                    */
  266.         *perr = OS_ERR_TMR_INVALID_TYPE;
  267.         return (0);
  268.     }
  269.     if (OSIntNesting > 0) {                            /* See if trying to call from an ISR                           */
  270.         *perr = OS_ERR_NAME_GET_ISR;
  271.         return (0);
  272.     }
  273.     OSSchedLock();
  274.     switch (ptmr->OSTmrState) {
  275.         case OS_TMR_STATE_RUNNING:
  276.         case OS_TMR_STATE_STOPPED:
  277.         case OS_TMR_STATE_COMPLETED:
  278.              pdest = ptmr->OSTmrName;
  279.              len   = OS_StrLen(pdest);
  280.              OSSchedUnlock();
  281.              *perr = OS_ERR_NONE;
  282.              return (len);
  283.         case OS_TMR_STATE_UNUSED:                      /* Timer is not allocated                                      */
  284.              OSSchedUnlock();
  285.              *perr = OS_ERR_TMR_INACTIVE;
  286.              return (0);
  287.         default:
  288.              OSSchedUnlock();
  289.              *perr = OS_ERR_TMR_INVALID_STATE;
  290.              return (0);
  291.     }
  292. }
  293. #endif
  294. /*$PAGE*/
  295. /*
  296. ************************************************************************************************************************
  297. *                                    GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
  298. *
  299. * Description: This function is called to get the number of ticks before a timer times out.
  300. *
  301. * Arguments  : ptmr          Is a pointer to the timer to obtain the remaining time from.
  302. *
  303. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  304. *                               OS_ERR_NONE
  305. *                               OS_ERR_TMR_INVALID        'ptmr' is a NULL pointer
  306. *                               OS_ERR_TMR_INVALID_TYPE   'ptmr'  is not pointing to an OS_TMR
  307. *                               OS_ERR_TMR_ISR            if the call was made from an ISR
  308. *                               OS_ERR_TMR_INACTIVE       'ptmr' points to a timer that is not active
  309. *                               OS_ERR_TMR_INVALID_STATE  the timer is in an invalid state
  310. *
  311. * Returns    : The time remaining for the timer to expire.  The time represents 'timer' increments.  In other words, if
  312. *              OSTmr_Task() is signaled every 1/10 of a second then the returned value represents the number of 1/10 of
  313. *              a second remaining before the timer expires.
  314. ************************************************************************************************************************
  315. */
  316. #if OS_TMR_EN > 0
  317. INT32U  OSTmrRemainGet (OS_TMR  *ptmr,
  318.                         INT8U   *perr)
  319. {
  320.     INT32U  remain;
  321. #if OS_ARG_CHK_EN > 0
  322.     if (perr == (INT8U *)0) {
  323.         return (0);
  324.     }
  325.     if (ptmr == (OS_TMR *)0) {
  326.         *perr = OS_ERR_TMR_INVALID;
  327.         return (0);
  328.     }
  329. #endif
  330.     if (ptmr->OSTmrType != OS_TMR_TYPE) {              /* Validate timer structure                                    */
  331.         *perr = OS_ERR_TMR_INVALID_TYPE;
  332.         return (0);
  333.     }
  334.     if (OSIntNesting > 0) {                            /* See if trying to call from an ISR                           */
  335.         *perr = OS_ERR_TMR_ISR;
  336.         return (0);
  337.     }
  338.     OSSchedLock();
  339.     switch (ptmr->OSTmrState) {
  340.         case OS_TMR_STATE_RUNNING:
  341.              remain = ptmr->OSTmrMatch - OSTmrTime;    /* Determine how much time is left to timeout                  */
  342.              OSSchedUnlock();
  343.              *perr  = OS_ERR_NONE;
  344.              return (remain);
  345.         case OS_TMR_STATE_STOPPED:                     /* It's assumed that the timer has not started yet             */
  346.              switch (ptmr->OSTmrOpt) {
  347.                  case OS_TMR_OPT_PERIODIC:
  348.                       if (ptmr->OSTmrDly == 0) {
  349.                           remain = ptmr->OSTmrPeriod;
  350.                       } else {
  351.                           remain = ptmr->OSTmrDly;
  352.                       }
  353.                       OSSchedUnlock();
  354.                       *perr  = OS_ERR_NONE;
  355.                       break;
  356.                  case OS_TMR_OPT_ONE_SHOT:
  357.                  default:
  358.                       remain = ptmr->OSTmrDly;
  359.                       OSSchedUnlock();
  360.                       *perr  = OS_ERR_NONE;
  361.                       break;
  362.              }
  363.              return (remain);
  364.         case OS_TMR_STATE_COMPLETED:                   /* Only ONE-SHOT that timed out can be in this state           */
  365.              OSSchedUnlock();
  366.              *perr = OS_ERR_NONE;
  367.              return (0);
  368.         case OS_TMR_STATE_UNUSED:
  369.              OSSchedUnlock();
  370.              *perr = OS_ERR_TMR_INACTIVE;
  371.              return (0);
  372.         default:
  373.              OSSchedUnlock();
  374.              *perr = OS_ERR_TMR_INVALID_STATE;
  375.              return (0);
  376.     }
  377. }
  378. #endif
  379. /*$PAGE*/
  380. /*
  381. ************************************************************************************************************************
  382. *                                    FIND OUT WHAT STATE A TIMER IS IN
  383. *
  384. * Description: This function is called to determine what state the timer is in:
  385. *
  386. *                  OS_TMR_STATE_UNUSED     the timer has not been created
  387. *                  OS_TMR_STATE_STOPPED    the timer has been created but has not been started or has been stopped
  388. *                  OS_TMR_COMPLETED        the timer is in ONE-SHOT mode and has completed it's timeout
  389. *                  OS_TMR_RUNNING          the timer is currently running
  390. *
  391. * Arguments  : ptmr          Is a pointer to the desired timer
  392. *
  393. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  394. *                               OS_ERR_NONE
  395. *                               OS_ERR_TMR_INVALID        'ptmr' is a NULL pointer
  396. *                               OS_ERR_TMR_INVALID_TYPE   'ptmr'  is not pointing to an OS_TMR
  397. *                               OS_ERR_TMR_ISR            if the call was made from an ISR
  398. *                               OS_ERR_TMR_INACTIVE       'ptmr' points to a timer that is not active
  399. *                               OS_ERR_TMR_INVALID_STATE  if the timer is not in a valid state
  400. *
  401. * Returns    : The current state of the timer (see description).
  402. ************************************************************************************************************************
  403. */
  404. #if OS_TMR_EN > 0
  405. INT8U  OSTmrStateGet (OS_TMR  *ptmr,
  406.                       INT8U   *perr)
  407. {
  408.     INT8U  state;
  409. #if OS_ARG_CHK_EN > 0
  410.     if (perr == (INT8U *)0) {
  411.         return (0);
  412.     }
  413.     if (ptmr == (OS_TMR *)0) {
  414.         *perr = OS_ERR_TMR_INVALID;
  415.         return (0);
  416.     }
  417. #endif
  418.     if (ptmr->OSTmrType != OS_TMR_TYPE) {              /* Validate timer structure                                    */
  419.         *perr = OS_ERR_TMR_INVALID_TYPE;
  420.         return (0);
  421.     }
  422.     if (OSIntNesting > 0) {                            /* See if trying to call from an ISR                           */
  423.         *perr = OS_ERR_TMR_ISR;
  424.         return (0);
  425.     }
  426.     OSSchedLock();
  427.     state = ptmr->OSTmrState;
  428.     switch (state) {
  429.         case OS_TMR_STATE_UNUSED:   
  430.         case OS_TMR_STATE_STOPPED:  
  431.         case OS_TMR_STATE_COMPLETED:
  432.         case OS_TMR_STATE_RUNNING:  
  433.              *perr = OS_ERR_NONE;
  434.              break;
  435.              
  436.         default:
  437.              *perr = OS_ERR_TMR_INVALID_STATE;
  438.              break;
  439.     }
  440.     OSSchedUnlock();
  441.     return (state);
  442. }
  443. #endif
  444. /*$PAGE*/
  445. /*
  446. ************************************************************************************************************************
  447. *                                                   START A TIMER
  448. *
  449. * Description: This function is called by your application code to start a timer.
  450. *
  451. * Arguments  : ptmr          Is a pointer to an OS_TMR
  452. *
  453. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  454. *                               OS_ERR_NONE
  455. *                               OS_ERR_TMR_INVALID
  456. *                               OS_ERR_TMR_INVALID_TYPE    'ptmr'  is not pointing to an OS_TMR
  457. *                               OS_ERR_TMR_ISR             if the call was made from an ISR
  458. *                               OS_ERR_TMR_INACTIVE        if the timer was not created
  459. *                               OS_ERR_TMR_INVALID_STATE   the timer is in an invalid state
  460. *
  461. * Returns    : OS_TRUE    if the timer was started
  462. *              OS_FALSE   if an error was detected
  463. ************************************************************************************************************************
  464. */
  465. #if OS_TMR_EN > 0
  466. BOOLEAN  OSTmrStart (OS_TMR   *ptmr,
  467.                      INT8U    *perr)
  468. {
  469. #if OS_ARG_CHK_EN > 0
  470.     if (perr == (INT8U *)0) {                               /* Validate arguments                                     */
  471.         return (OS_FALSE);
  472.     }
  473.     if (ptmr == (OS_TMR *)0) {
  474.         *perr = OS_ERR_TMR_INVALID;
  475.         return (OS_FALSE);
  476.     }
  477. #endif
  478.     if (ptmr->OSTmrType != OS_TMR_TYPE) {                   /* Validate timer structure                               */
  479.         *perr = OS_ERR_TMR_INVALID_TYPE;
  480.         return (OS_FALSE);
  481.     }
  482.     if (OSIntNesting > 0) {                                 /* See if trying to call from an ISR                      */
  483.         *perr  = OS_ERR_TMR_ISR;
  484.         return (OS_FALSE);
  485.     }
  486.     OSSchedLock();
  487.     switch (ptmr->OSTmrState) {
  488.         case OS_TMR_STATE_RUNNING:                          /* Restart the timer                                      */
  489.              OSTmr_Unlink(ptmr);                            /* ... Stop the timer                                     */
  490.              OSTmr_Link(ptmr, OS_TMR_LINK_DLY);             /* ... Link timer to timer wheel                          */
  491.              OSSchedUnlock();
  492.              *perr = OS_ERR_NONE;
  493.              return (OS_TRUE);
  494.         case OS_TMR_STATE_STOPPED:                          /* Start the timer                                        */
  495.         case OS_TMR_STATE_COMPLETED:
  496.              OSTmr_Link(ptmr, OS_TMR_LINK_DLY);             /* ... Link timer to timer wheel                          */
  497.              OSSchedUnlock();
  498.              *perr = OS_ERR_NONE;
  499.              return (OS_TRUE);
  500.         case OS_TMR_STATE_UNUSED:                           /* Timer not created                                      */
  501.              OSSchedUnlock();
  502.              *perr = OS_ERR_TMR_INACTIVE;
  503.              return (OS_FALSE);
  504.         default:
  505.              OSSchedUnlock();
  506.              *perr = OS_ERR_TMR_INVALID_STATE;
  507.              return (OS_FALSE);
  508.     }
  509. }
  510. #endif
  511. /*$PAGE*/
  512. /*
  513. ************************************************************************************************************************
  514. *                                                   STOP A TIMER
  515. *
  516. * Description: This function is called by your application code to stop a timer.
  517. *
  518. * Arguments  : ptmr          Is a pointer to the timer to stop.
  519. *
  520. *              opt           Allows you to specify an option to this functions which can be:
  521. *
  522. *                               OS_TMR_OPT_NONE          Do nothing special but stop the timer
  523. *                               OS_TMR_OPT_CALLBACK      Execute the callback function, pass it the callback argument
  524. *                                                        specified when the timer was created.
  525. *                               OS_TMR_OPT_CALLBACK_ARG  Execute the callback function, pass it the callback argument
  526. *                                                        specified in THIS function call
  527. *
  528. *              callback_arg  Is a pointer to a 'new' callback argument that can be passed to the callback function
  529. *                               instead of the timer's callback argument.  In other words, use 'callback_arg' passed in
  530. *                               THIS function INSTEAD of ptmr->OSTmrCallbackArg
  531. *
  532. *              perr          Is a pointer to an error code.  '*perr' will contain one of the following:
  533. *                               OS_ERR_NONE
  534. *                               OS_ERR_TMR_INVALID         'ptmr' is a NULL pointer
  535. *                               OS_ERR_TMR_INVALID_TYPE    'ptmr'  is not pointing to an OS_TMR
  536. *                               OS_ERR_TMR_ISR             if the function was called from an ISR
  537. *                               OS_ERR_TMR_INACTIVE        if the timer was not created
  538. *                               OS_ERR_TMR_INVALID_OPT     if you specified an invalid option for 'opt'
  539. *                               OS_ERR_TMR_STOPPED         if the timer was already stopped
  540. *                               OS_ERR_TMR_INVALID_STATE   the timer is in an invalid state
  541. *                               OS_ERR_TMR_NO_CALLBACK     if the timer does not have a callback function defined
  542. *
  543. * Returns    : OS_TRUE       If we stopped the timer (if the timer is already stopped, we also return OS_TRUE)
  544. *              OS_FALSE      If not
  545. ************************************************************************************************************************
  546. */
  547. #if OS_TMR_EN > 0
  548. BOOLEAN  OSTmrStop (OS_TMR  *ptmr,
  549.                     INT8U    opt,
  550.                     void    *callback_arg,
  551.                     INT8U   *perr)
  552. {
  553.     OS_TMR_CALLBACK  pfnct;
  554. #if OS_ARG_CHK_EN > 0
  555.     if (perr == (INT8U *)0) {                                     /* Validate arguments                               */
  556.         return (OS_FALSE);
  557.     }
  558.     if (ptmr == (OS_TMR *)0) {
  559.         *perr = OS_ERR_TMR_INVALID;
  560.         return (OS_FALSE);
  561.     }
  562. #endif
  563.     if (ptmr->OSTmrType != OS_TMR_TYPE) {                         /* Validate timer structure                         */
  564.         *perr = OS_ERR_TMR_INVALID_TYPE;
  565.         return (OS_FALSE);
  566.     }
  567.     if (OSIntNesting > 0) {                                       /* See if trying to call from an ISR                */
  568.         *perr  = OS_ERR_TMR_ISR;
  569.         return (OS_FALSE);
  570.     }
  571.     OSSchedLock();
  572.     switch (ptmr->OSTmrState) {
  573.         case OS_TMR_STATE_RUNNING:
  574.              OSTmr_Unlink(ptmr);                                  /* Remove from current wheel spoke                  */
  575.              *perr = OS_ERR_NONE;
  576.              switch (opt) {
  577.                  case OS_TMR_OPT_CALLBACK:
  578.                       pfnct = ptmr->OSTmrCallback;                /* Execute callback function if available ...       */
  579.                       if (pfnct != (OS_TMR_CALLBACK)0) {
  580.                           (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg);  /* Use callback arg when timer was created */
  581.                       } else {
  582.                           *perr = OS_ERR_TMR_NO_CALLBACK;
  583.                       }
  584.                       break;
  585.                  case OS_TMR_OPT_CALLBACK_ARG:
  586.                       pfnct = ptmr->OSTmrCallback;                /* Execute callback function if available ...       */
  587.                       if (pfnct != (OS_TMR_CALLBACK)0) {
  588.                           (*pfnct)((void *)ptmr, callback_arg);   /* ... using the 'callback_arg' provided in call    */
  589.                       } else {
  590.                           *perr = OS_ERR_TMR_NO_CALLBACK;
  591.                       }
  592.                       break;
  593.                  case OS_TMR_OPT_NONE:
  594.                       break;
  595.                  default:
  596.                      *perr = OS_ERR_TMR_INVALID_OPT;
  597.                      break;
  598.              }
  599.              OSSchedUnlock();
  600.              return (OS_TRUE);
  601.         case OS_TMR_STATE_COMPLETED:                              /* Timer has already completed the ONE-SHOT or ...  */
  602.         case OS_TMR_STATE_STOPPED:                                /* ... timer has not started yet.                   */
  603.              OSSchedUnlock();
  604.              *perr = OS_ERR_TMR_STOPPED;
  605.              return (OS_TRUE);
  606.         case OS_TMR_STATE_UNUSED:                                 /* Timer was not created                            */
  607.              OSSchedUnlock();
  608.              *perr = OS_ERR_TMR_INACTIVE;
  609.              return (OS_FALSE);
  610.         default:
  611.              OSSchedUnlock();
  612.              *perr = OS_ERR_TMR_INVALID_STATE;
  613.              return (OS_FALSE);
  614.     }
  615. }
  616. #endif
  617. /*$PAGE*/
  618. /*
  619. ************************************************************************************************************************
  620. *                                      SIGNAL THAT IT'S TIME TO UPDATE THE TIMERS
  621. *
  622. * Description: This function is typically called by the ISR that occurs at the timer tick rate and is used to signal to
  623. *              OSTmr_Task() that it's time to update the timers.
  624. *
  625. * Arguments  : none
  626. *
  627. * Returns    : OS_ERR_NONE         The call was successful and the timer task was signaled.
  628. *              OS_ERR_SEM_OVF      If OSTmrSignal() was called more often than OSTmr_Task() can handle the timers.  
  629. *                                  This would indicate that your system is heavily loaded.
  630. *              OS_ERR_EVENT_TYPE   Unlikely you would get this error because the semaphore used for signaling is created 
  631. *                                  by uC/OS-II.
  632. *              OS_ERR_PEVENT_NULL  Again, unlikely you would ever get this error because the semaphore used for signaling 
  633. *                                  is created by uC/OS-II.
  634. ************************************************************************************************************************
  635. */
  636. #if OS_TMR_EN > 0
  637. INT8U  OSTmrSignal (void)
  638. {
  639.     INT8U  err;
  640.     err = OSSemPost(OSTmrSemSignal);
  641.     return (err);
  642. }
  643. #endif
  644. /*$PAGE*/
  645. /*
  646. ************************************************************************************************************************
  647. *                                               ALLOCATE AND FREE A TIMER
  648. *
  649. * Description: This function is called to allocate a timer.
  650. *
  651. * Arguments  : none
  652. *
  653. * Returns    : a pointer to a timer if one is available
  654. ************************************************************************************************************************
  655. */
  656. #if OS_TMR_EN > 0
  657. static  OS_TMR  *OSTmr_Alloc (void)
  658. {
  659.     OS_TMR *ptmr;
  660.     if (OSTmrFreeList == (OS_TMR *)0) {
  661.         return ((OS_TMR *)0);
  662.     }
  663.     ptmr            = (OS_TMR *)OSTmrFreeList;
  664.     OSTmrFreeList   = (OS_TMR *)ptmr->OSTmrNext;
  665.     ptmr->OSTmrNext = (OS_TCB *)0;
  666.     ptmr->OSTmrPrev = (OS_TCB *)0;
  667.     OSTmrUsed++;
  668.     OSTmrFree--;
  669.     return (ptmr);
  670. }
  671. #endif
  672. /*
  673. ************************************************************************************************************************
  674. *                                             RETURN A TIMER TO THE FREE LIST
  675. *
  676. * Description: This function is called to return a timer object to the free list of timers.
  677. *
  678. * Arguments  : ptmr     is a pointer to the timer to free
  679. *
  680. * Returns    : none
  681. ************************************************************************************************************************
  682. */
  683. #if OS_TMR_EN > 0
  684. static  void  OSTmr_Free (OS_TMR *ptmr)
  685. {
  686.     ptmr->OSTmrState       = OS_TMR_STATE_UNUSED;      /* Clear timer object fields                                   */
  687.     ptmr->OSTmrOpt         = OS_TMR_OPT_NONE;
  688.     ptmr->OSTmrPeriod      = 0;
  689.     ptmr->OSTmrMatch       = 0;
  690.     ptmr->OSTmrCallback    = (OS_TMR_CALLBACK)0;
  691.     ptmr->OSTmrCallbackArg = (void *)0;
  692. #if OS_TMR_CFG_NAME_EN > 0
  693.     ptmr->OSTmrName        = "?";                      /* Unknown name                                                */
  694. #endif
  695.     ptmr->OSTmrPrev        = (OS_TCB *)0;              /* Chain timer to free list                                    */
  696.     ptmr->OSTmrNext        = OSTmrFreeList;
  697.     OSTmrFreeList          = ptmr;
  698.     OSTmrUsed--;                                       /* Update timer object statistics                              */
  699.     OSTmrFree++;
  700. }
  701. #endif
  702. /*$PAGE*/
  703. /*
  704. ************************************************************************************************************************
  705. *                                                    INITIALIZATION
  706. *                                          INITIALIZE THE FREE LIST OF TIMERS
  707. *
  708. * Description: This function is called by OSInit() to initialize the free list of OS_TMRs.
  709. *
  710. * Arguments  : none
  711. *
  712. * Returns    : none
  713. ************************************************************************************************************************
  714. */
  715. #if OS_TMR_EN > 0
  716. void  OSTmr_Init (void)
  717. {
  718. #if OS_EVENT_NAME_EN > 0
  719.     INT8U    err;
  720. #endif
  721.     INT16U   i;
  722.     OS_TMR  *ptmr1;
  723.     OS_TMR  *ptmr2;
  724.     OS_MemClr((INT8U *)&OSTmrTbl[0],      sizeof(OSTmrTbl));            /* Clear all the TMRs                         */
  725.     OS_MemClr((INT8U *)&OSTmrWheelTbl[0], sizeof(OSTmrWheelTbl));       /* Clear the timer wheel                      */
  726.     ptmr1 = &OSTmrTbl[0];
  727.     ptmr2 = &OSTmrTbl[1];
  728.     for (i = 0; i < (OS_TMR_CFG_MAX - 1); i++) {                        /* Init. list of free TMRs                    */
  729.         ptmr1->OSTmrType    = OS_TMR_TYPE;
  730.         ptmr1->OSTmrState   = OS_TMR_STATE_UNUSED;                      /* Indicate that timer is inactive            */
  731.         ptmr1->OSTmrNext    = (void *)ptmr2;                            /* Link to next timer                         */
  732. #if OS_TMR_CFG_NAME_EN > 0
  733.         ptmr1->OSTmrName    = "?";                                      /* Unknown name                               */
  734. #endif
  735.         ptmr1++;
  736.         ptmr2++;
  737.     }
  738.     ptmr1->OSTmrType    = OS_TMR_TYPE;
  739.     ptmr1->OSTmrState   = OS_TMR_STATE_UNUSED;                          /* Indicate that timer is inactive            */
  740.     ptmr1->OSTmrNext    = (void *)0;                                    /* Last OS_TMR                                */
  741. #if OS_TMR_CFG_NAME_EN > 0
  742.     ptmr1->OSTmrName    = "?";                                          /* Unknown name                               */
  743. #endif
  744.     OSTmrTime           = 0;
  745.     OSTmrUsed           = 0;
  746.     OSTmrFree           = OS_TMR_CFG_MAX;
  747.     OSTmrFreeList       = &OSTmrTbl[0];
  748.     OSTmrSem            = OSSemCreate(1);
  749.     OSTmrSemSignal      = OSSemCreate(0);
  750. #if OS_EVENT_NAME_EN > 0
  751.     OSEventNameSet(OSTmrSem,       (INT8U *)"uC/OS-II TmrLock",   &err);/* Assign names to semaphores                 */
  752.     OSEventNameSet(OSTmrSemSignal, (INT8U *)"uC/OS-II TmrSignal", &err);
  753. #endif
  754.     OSTmr_InitTask();
  755. }
  756. #endif
  757. /*$PAGE*/
  758. /*
  759. ************************************************************************************************************************
  760. *                                          INITIALIZE THE TIMER MANAGEMENT TASK
  761. *
  762. * Description: This function is called by OSTmrInit() to create the timer management task.
  763. *                               * Arguments  : none
  764. *
  765. * Returns    : none
  766. ************************************************************************************************************************
  767. */
  768. #if OS_TMR_EN > 0
  769. static  void  OSTmr_InitTask (void)
  770. {
  771. #if OS_TASK_NAME_EN > 0
  772.     INT8U  err;
  773. #endif
  774. #if OS_TASK_CREATE_EXT_EN > 0
  775.     #if OS_STK_GROWTH == 1
  776.     (void)OSTaskCreateExt(OSTmr_Task,
  777.                           (void *)0,                                       /* No arguments passed to OSTmrTask()      */
  778.                           &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1],         /* Set Top-Of-Stack                        */
  779.                           OS_TASK_TMR_PRIO,
  780.                           OS_TASK_TMR_ID,
  781.                           &OSTmrTaskStk[0],                                /* Set Bottom-Of-Stack                     */
  782.                           OS_TASK_TMR_STK_SIZE,
  783.                           (void *)0,                                       /* No TCB extension                        */
  784.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);      /* Enable stack checking + clear stack     */
  785.     #else
  786.     (void)OSTaskCreateExt(OSTmr_Task,
  787.                           (void *)0,                                       /* No arguments passed to OSTmrTask()      */
  788.                           &OSTmrTaskStk[0],                                /* Set Top-Of-Stack                        */
  789.                           OS_TASK_TMR_PRIO,
  790.                           OS_TASK_TMR_ID,
  791.                           &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1],         /* Set Bottom-Of-Stack                     */
  792.                           OS_TASK_TMR_STK_SIZE,
  793.                           (void *)0,                                       /* No TCB extension                        */
  794.                           OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);      /* Enable stack checking + clear stack     */
  795.     #endif
  796. #else
  797.     #if OS_STK_GROWTH == 1
  798.     (void)OSTaskCreate(OSTmr_Task,
  799.                        (void *)0,
  800.                        &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1],
  801.                        OS_TASK_TMR_PRIO);
  802.     #else
  803.     (void)OSTaskCreate(OSTmr_Task,
  804.                        (void *)0,
  805.                        &OSTmrTaskStk[0],
  806.                        OS_TASK_TMR_PRIO);
  807.     #endif
  808. #endif
  809. #if OS_TASK_NAME_EN > 0
  810.     OSTaskNameSet(OS_TASK_TMR_PRIO, (INT8U *)"uC/OS-II Tmr", &err);
  811. #endif
  812. }
  813. #endif
  814. /*$PAGE*/
  815. /*
  816. ************************************************************************************************************************
  817. *                                         INSERT A TIMER INTO THE TIMER WHEEL
  818. *
  819. * Description: This function is called to insert the timer into the timer wheel.  The timer is always inserted at the
  820. *              beginning of the list.
  821. *
  822. * Arguments  : ptmr          Is a pointer to the timer to insert.
  823. *
  824. *              type          Is either:
  825. *                               OS_TMR_LINK_PERIODIC    Means to re-insert the timer after a period expired
  826. *                               OS_TMR_LINK_DLY         Means to insert    the timer the first time
  827. *
  828. * Returns    : none
  829. ************************************************************************************************************************
  830. */
  831. #if OS_TMR_EN > 0
  832. static  void  OSTmr_Link (OS_TMR  *ptmr, 
  833.                           INT8U    type)
  834. {
  835.     OS_TMR       *ptmr1;
  836.     OS_TMR_WHEEL *pspoke;
  837.     INT16U        spoke;
  838.     ptmr->OSTmrState = OS_TMR_STATE_RUNNING;
  839.     if (type == OS_TMR_LINK_PERIODIC) {                            /* Determine when timer will expire                */
  840.         ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
  841.     } else {
  842.         if (ptmr->OSTmrDly == 0) {
  843.             ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
  844.         } else {
  845.             ptmr->OSTmrMatch = ptmr->OSTmrDly    + OSTmrTime;
  846.         }
  847.     }
  848.     spoke  = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
  849.     pspoke = &OSTmrWheelTbl[spoke];
  850.     if (pspoke->OSTmrFirst == (OS_TMR *)0) {                       /* Link into timer wheel                           */
  851.         pspoke->OSTmrFirst   = ptmr;
  852.         ptmr->OSTmrNext      = (OS_TMR *)0;
  853.         pspoke->OSTmrEntries = 1;
  854.     } else {
  855.         ptmr1                = pspoke->OSTmrFirst;                 /* Point to first timer in the spoke               */
  856.         pspoke->OSTmrFirst   = ptmr;
  857.         ptmr->OSTmrNext      = (void *)ptmr1;
  858.         ptmr1->OSTmrPrev     = (void *)ptmr;
  859.         pspoke->OSTmrEntries++;
  860.     }
  861.     ptmr->OSTmrPrev = (void *)0;                                   /* Timer always inserted as first node in list     */
  862. }
  863. #endif
  864. /*$PAGE*/
  865. /*
  866. ************************************************************************************************************************
  867. *                                         REMOVE A TIMER FROM THE TIMER WHEEL
  868. *
  869. * Description: This function is called to remove the timer from the timer wheel.
  870. *
  871. * Arguments  : ptmr          Is a pointer to the timer to remove.
  872. *
  873. * Returns    : none
  874. ************************************************************************************************************************
  875. */
  876. #if OS_TMR_EN > 0
  877. static  void  OSTmr_Unlink (OS_TMR *ptmr)
  878. {
  879.     OS_TMR        *ptmr1;
  880.     OS_TMR        *ptmr2;
  881.     OS_TMR_WHEEL  *pspoke;
  882.     INT16U         spoke;
  883.     spoke  = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
  884.     pspoke = &OSTmrWheelTbl[spoke];
  885.     if (pspoke->OSTmrFirst == ptmr) {                       /* See if timer to remove is at the beginning of list     */
  886.         ptmr1              = (OS_TMR *)ptmr->OSTmrNext;
  887.         pspoke->OSTmrFirst = (OS_TMR *)ptmr1;
  888.         if (ptmr1 != (OS_TMR *)0) {
  889.             ptmr1->OSTmrPrev = (void *)0;
  890.         }
  891.     } else {
  892.         ptmr1            = (OS_TMR *)ptmr->OSTmrPrev;       /* Remove timer from somewhere in the list                */
  893.         ptmr2            = (OS_TMR *)ptmr->OSTmrNext;
  894.         ptmr1->OSTmrNext = ptmr2;
  895.         if (ptmr2 != (OS_TMR *)0) {
  896.             ptmr2->OSTmrPrev = (void *)ptmr1;
  897.         }
  898.     }
  899.     ptmr->OSTmrState = OS_TMR_STATE_STOPPED;
  900.     ptmr->OSTmrNext  = (void *)0;
  901.     ptmr->OSTmrPrev  = (void *)0;
  902.     pspoke->OSTmrEntries--;
  903. }
  904. #endif
  905. /*$PAGE*/
  906. /*
  907. ************************************************************************************************************************
  908. *                                                 TIMER MANAGEMENT TASK
  909. *
  910. * Description: This task is created by OSTmrInit().
  911. *
  912. * Arguments  : none
  913. *
  914. * Returns    : none
  915. ************************************************************************************************************************
  916. */
  917. #if OS_TMR_EN > 0
  918. static  void  OSTmr_Task (void *p_arg)
  919. {
  920.     INT8U            err;
  921.     OS_TMR          *ptmr;
  922.     OS_TMR          *ptmr_next;
  923.     OS_TMR_CALLBACK  pfnct;
  924.     OS_TMR_WHEEL    *pspoke;
  925.     INT16U           spoke;
  926.     (void)p_arg;                                                 /* Not using 'p_arg', prevent compiler warning       */
  927.     for (;;) {
  928.         OSSemPend(OSTmrSemSignal, 0, &err);                      /* Wait for signal indicating time to update timers  */
  929.         OSSchedLock();
  930.         OSTmrTime++;                                             /* Increment the current time                        */
  931.         spoke  = (INT16U)(OSTmrTime % OS_TMR_CFG_WHEEL_SIZE);    /* Position on current timer wheel entry             */
  932.         pspoke = &OSTmrWheelTbl[spoke];
  933.         ptmr   = pspoke->OSTmrFirst;
  934.         while (ptmr != (OS_TMR *)0) {
  935.             ptmr_next = (OS_TMR *)ptmr->OSTmrNext;               /* Point to next timer to update because current ... */
  936.                                                                  /* ... timer could get unlinked from the wheel.      */
  937.             if (OSTmrTime == ptmr->OSTmrMatch) {                 /* Process each timer that expires                   */
  938.                 OSTmr_Unlink(ptmr);                              /* Remove from current wheel spoke                   */
  939.                 if (ptmr->OSTmrOpt == OS_TMR_OPT_PERIODIC) {
  940.                     OSTmr_Link(ptmr, OS_TMR_LINK_PERIODIC);      /* Recalculate new position of timer in wheel        */
  941.                 } else {
  942.                     ptmr->OSTmrState = OS_TMR_STATE_COMPLETED;   /* Indicate that the timer has completed             */
  943.                 }
  944.                 pfnct = ptmr->OSTmrCallback;                     /* Execute callback function if available            */
  945.                 if (pfnct != (OS_TMR_CALLBACK)0) {
  946.                     (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg);
  947.                 }
  948.             }
  949.             ptmr = ptmr_next;
  950.         }
  951.         OSSchedUnlock();
  952.     }
  953. }
  954. #endif