]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - src/timer.c
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called...
[CanFestival-3.git] / src / timer.c
1 /*
2 This file is part of CanFestival, a library implementing CanOpen Stack. 
3
4 Copyright (C): Edouard TISSERANT and Francis DUPIN
5
6 See COPYING file for copyrights details.
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22 /*!
23 ** @file   timer.c
24 ** @author Edouard TISSERANT and Francis DUPIN
25 ** @date   Tue Jun  5 09:32:32 2007
26 **
27 ** @brief
28 **
29 **
30 */
31
32 /* #define DEBUG_WAR_CONSOLE_ON */
33 /* #define DEBUG_ERR_CONSOLE_ON */
34
35 #include <applicfg.h>
36 #include "timer.h"
37
38 /*  ---------  The timer table --------- */
39 s_timer_entry timers[MAX_NB_TIMER] = {{TIMER_FREE, NULL, NULL, 0, 0, 0},};
40
41 TIMEVAL total_sleep_time = TIMEVAL_MAX;
42 TIMER_HANDLE last_timer_raw = -1;
43
44 #define min_val(a,b) ((a<b)?a:b)
45
46 /*!                                                                                                
47 ** -------  Use this to declare a new alarm ------                                                                                                
48 **                                                                                                 
49 ** @param d                                                                                        
50 ** @param id                                                                                       
51 ** @param callback                                                                                 
52 ** @param value                                                                                    
53 ** @param period                                                                                   
54 **                                                                                                 
55 ** @return                                                                                         
56 **/   
57 TIMER_HANDLE SetAlarm(CO_Data* d, UNS32 id, TimerCallback_t callback, TIMEVAL value, TIMEVAL period)
58 {
59         TIMER_HANDLE row_number;
60         s_timer_entry *row;
61
62         /* in order to decide new timer setting we have to run over all timer rows */
63         for(row_number=0, row=timers; row_number <= last_timer_raw + 1 && row_number < MAX_NB_TIMER; row_number++, row++)
64         {
65                 if (callback &&         /* if something to store */
66                    row->state == TIMER_FREE) /* and empty row */
67                 {       /* just store */
68                         TIMEVAL real_timer_value;
69                         TIMEVAL elapsed_time;
70                         
71                         if (row_number == last_timer_raw + 1) last_timer_raw++;
72                         
73                         elapsed_time = getElapsedTime();
74                         /* set next wakeup alarm if new entry is sooner than others, or if it is alone */
75                         real_timer_value = value > elapsed_time ? value - elapsed_time : 0;
76                         real_timer_value = min_val(real_timer_value, TIMEVAL_MAX);
77         
78                         if (total_sleep_time > elapsed_time && total_sleep_time - elapsed_time > real_timer_value)
79                         {
80                                 total_sleep_time = elapsed_time + real_timer_value;
81                                 setTimer(real_timer_value);
82                         }
83                         row->callback = callback;
84                         row->d = d;
85                         row->id = id;
86                         row->val = value + elapsed_time;
87                         row->interval = period;
88                         row->state = TIMER_ARMED;
89                         return row_number;
90                 }
91         }
92         
93         return TIMER_NONE;
94 }
95
96 /*!                                                                                                
97 **  -----  Use this to remove an alarm ----                                                                                             
98 **                                                                                                 
99 ** @param handle                                                                                   
100 **                                                                                                 
101 ** @return                                                                                         
102 **/  
103 TIMER_HANDLE DelAlarm(TIMER_HANDLE handle)
104 {
105         /* Quick and dirty. system timer will continue to be trigged, but no action will be preformed. */
106         MSG_WAR(0x3320, "DelAlarm. handle = ", handle);
107         if(handle != TIMER_NONE)
108         {
109                 if(handle == last_timer_raw) 
110                         last_timer_raw--;
111                 timers[handle].state = TIMER_FREE;              
112         }
113         return TIMER_NONE;
114 }
115
116 /*!                                                                                                
117 ** ------  TimeDispatch is called on each timer expiration ----                                                                                                
118 **                                                                                                 
119 **/
120 int tdcount=0;  
121 void TimeDispatch(void)
122 {
123         TIMER_HANDLE i;
124         TIMEVAL next_wakeup = TIMEVAL_MAX; /* used to compute when should normaly occur next wakeup */
125         /* First run : change timer state depending on time */
126         /* Get time since timer signal */
127         TIMEVAL overrun = getElapsedTime();
128         
129         TIMEVAL real_total_sleep_time = total_sleep_time + overrun;
130
131         s_timer_entry *row;
132
133         for(i=0, row = timers; i <= last_timer_raw; i++, row++)
134         {
135                 if (row->state & TIMER_ARMED) /* if row is active */
136                 {
137                         if (row->val <= real_total_sleep_time) /* to be trigged */
138                         {
139                                 if (!row->interval) /* if simply outdated */
140                                 {
141                                         row->state = TIMER_TRIG; /* ask for trig */
142                                 }
143                                 else /* or period have expired */
144                                 {
145                                         /* set val as interval, with overrun correction */
146                                         row->val = row->interval - (overrun % row->interval);
147                                         row->state = TIMER_TRIG_PERIOD; /* ask for trig, periodic */
148                                         /* Check if this new timer value is the soonest */
149                                         if(row->val < next_wakeup)
150                                                 next_wakeup = row->val;   
151                                 }
152                         }
153                         else
154                         {
155                                 /* Each armed timer value in decremented. */
156                                 row->val -= real_total_sleep_time;
157
158                                 /* Check if this new timer value is the soonest */
159                                 if(row->val < next_wakeup)
160                                         next_wakeup = row->val;   
161                         }
162                 }
163         }
164         
165         /* Remember how much time we should sleep. */
166         total_sleep_time = next_wakeup;
167
168         /* Set timer to soonest occurence */
169         setTimer(next_wakeup);
170
171         /* Then trig them or not. */
172         for(i=0, row = timers; i<=last_timer_raw; i++, row++)
173         {
174                 if (row->state & TIMER_TRIG)
175                 {
176                         row->state &= ~TIMER_TRIG; /* reset trig state (will be free if not periodic) */
177                         if(row->callback)
178                                 (*row->callback)(row->d, row->id); /* trig ! */
179                 }
180         }
181 }