author | Christian Taedcke <hacking@taedcke.com> |
Thu, 27 Jan 2011 17:45:48 +0100 | |
changeset 654 | fc9af616633d |
parent 629 | b9274b595650 |
child 801 | 32d146b64a35 |
permissions | -rwxr-xr-x |
38 | 1 |
/* |
576 | 2 |
This file is part of CanFestival, a library implementing CanOpen Stack. |
38 | 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 |
*/ |
|
208 | 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 |
*/ |
|
38 | 31 |
|
71 | 32 |
/* #define DEBUG_WAR_CONSOLE_ON */ |
33 |
/* #define DEBUG_ERR_CONSOLE_ON */ |
|
38 | 34 |
|
35 |
#include <applicfg.h> |
|
36 |
#include "timer.h" |
|
37 |
||
71 | 38 |
/* --------- The timer table --------- */ |
38 | 39 |
s_timer_entry timers[MAX_NB_TIMER] = {{TIMER_FREE, NULL, NULL, 0, 0, 0},}; |
71 | 40 |
|
38 | 41 |
TIMEVAL total_sleep_time = TIMEVAL_MAX; |
42 |
TIMER_HANDLE last_timer_raw = -1; |
|
43 |
||
167 | 44 |
#define min_val(a,b) ((a<b)?a:b) |
38 | 45 |
|
576 | 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 |
**/ |
|
38 | 57 |
TIMER_HANDLE SetAlarm(CO_Data* d, UNS32 id, TimerCallback_t callback, TIMEVAL value, TIMEVAL period) |
58 |
{ |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
59 |
TIMER_HANDLE row_number; |
470 | 60 |
s_timer_entry *row; |
38 | 61 |
|
215 | 62 |
/* in order to decide new timer setting we have to run over all timer rows */ |
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
63 |
for(row_number=0, row=timers; row_number <= last_timer_raw + 1 && row_number < MAX_NB_TIMER; row_number++, row++) |
38 | 64 |
{ |
215 | 65 |
if (callback && /* if something to store */ |
66 |
row->state == TIMER_FREE) /* and empty row */ |
|
67 |
{ /* just store */ |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
68 |
TIMEVAL real_timer_value; |
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
69 |
TIMEVAL elapsed_time; |
576 | 70 |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
71 |
if (row_number == last_timer_raw + 1) last_timer_raw++; |
576 | 72 |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
73 |
elapsed_time = getElapsedTime(); |
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
74 |
/* set next wakeup alarm if new entry is sooner than others, or if it is alone */ |
576 | 75 |
real_timer_value = value; |
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
76 |
real_timer_value = min_val(real_timer_value, TIMEVAL_MAX); |
576 | 77 |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
78 |
if (total_sleep_time > elapsed_time && total_sleep_time - elapsed_time > real_timer_value) |
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
79 |
{ |
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
80 |
total_sleep_time = elapsed_time + real_timer_value; |
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
81 |
setTimer(real_timer_value); |
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
82 |
} |
38 | 83 |
row->callback = callback; |
84 |
row->d = d; |
|
85 |
row->id = id; |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
86 |
row->val = value + elapsed_time; |
38 | 87 |
row->interval = period; |
88 |
row->state = TIMER_ARMED; |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
89 |
return row_number; |
38 | 90 |
} |
91 |
} |
|
576 | 92 |
|
38 | 93 |
return TIMER_NONE; |
94 |
} |
|
95 |
||
576 | 96 |
/*! |
97 |
** ----- Use this to remove an alarm ---- |
|
98 |
** |
|
99 |
** @param handle |
|
100 |
** |
|
101 |
** @return |
|
102 |
**/ |
|
38 | 103 |
TIMER_HANDLE DelAlarm(TIMER_HANDLE handle) |
104 |
{ |
|
215 | 105 |
/* Quick and dirty. system timer will continue to be trigged, but no action will be preformed. */ |
38 | 106 |
MSG_WAR(0x3320, "DelAlarm. handle = ", handle); |
107 |
if(handle != TIMER_NONE) |
|
108 |
{ |
|
576 | 109 |
if(handle == last_timer_raw) |
38 | 110 |
last_timer_raw--; |
576 | 111 |
timers[handle].state = TIMER_FREE; |
38 | 112 |
} |
113 |
return TIMER_NONE; |
|
114 |
} |
|
115 |
||
576 | 116 |
/*! |
117 |
** ------ TimeDispatch is called on each timer expiration ---- |
|
118 |
** |
|
522
e69d5903a5b2
Fixed serious bug in setAlarm, causing wrong timer duration when setAlarm not called long after timeDispatch.
greg
parents:
470
diff
changeset
|
119 |
**/ |
576 | 120 |
int tdcount=0; |
470 | 121 |
void TimeDispatch(void) |
38 | 122 |
{ |
123 |
TIMER_HANDLE i; |
|
215 | 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 */ |
|
629 | 127 |
UNS32 overrun = (UNS32)getElapsedTime(); |
576 | 128 |
|
38 | 129 |
TIMEVAL real_total_sleep_time = total_sleep_time + overrun; |
130 |
||
470 | 131 |
s_timer_entry *row; |
132 |
||
133 |
for(i=0, row = timers; i <= last_timer_raw; i++, row++) |
|
38 | 134 |
{ |
215 | 135 |
if (row->state & TIMER_ARMED) /* if row is active */ |
38 | 136 |
{ |
215 | 137 |
if (row->val <= real_total_sleep_time) /* to be trigged */ |
38 | 138 |
{ |
215 | 139 |
if (!row->interval) /* if simply outdated */ |
38 | 140 |
{ |
215 | 141 |
row->state = TIMER_TRIG; /* ask for trig */ |
38 | 142 |
} |
215 | 143 |
else /* or period have expired */ |
38 | 144 |
{ |
629 | 145 |
/* set val as interval, with 32 bit overrun correction, */ |
146 |
/* modulo for 64 bit not available on all platforms */ |
|
147 |
row->val = row->interval - (overrun % (UNS32)row->interval); |
|
71 | 148 |
row->state = TIMER_TRIG_PERIOD; /* ask for trig, periodic */ |
215 | 149 |
/* Check if this new timer value is the soonest */ |
470 | 150 |
if(row->val < next_wakeup) |
576 | 151 |
next_wakeup = row->val; |
38 | 152 |
} |
153 |
} |
|
154 |
else |
|
155 |
{ |
|
215 | 156 |
/* Each armed timer value in decremented. */ |
38 | 157 |
row->val -= real_total_sleep_time; |
158 |
||
215 | 159 |
/* Check if this new timer value is the soonest */ |
470 | 160 |
if(row->val < next_wakeup) |
576 | 161 |
next_wakeup = row->val; |
38 | 162 |
} |
163 |
} |
|
164 |
} |
|
576 | 165 |
|
215 | 166 |
/* Remember how much time we should sleep. */ |
38 | 167 |
total_sleep_time = next_wakeup; |
168 |
||
215 | 169 |
/* Set timer to soonest occurence */ |
38 | 170 |
setTimer(next_wakeup); |
171 |
||
215 | 172 |
/* Then trig them or not. */ |
470 | 173 |
for(i=0, row = timers; i<=last_timer_raw; i++, row++) |
38 | 174 |
{ |
175 |
if (row->state & TIMER_TRIG) |
|
176 |
{ |
|
215 | 177 |
row->state &= ~TIMER_TRIG; /* reset trig state (will be free if not periodic) */ |
149 | 178 |
if(row->callback) |
215 | 179 |
(*row->callback)(row->d, row->id); /* trig ! */ |
38 | 180 |
} |
181 |
} |
|
182 |
} |