Removed 'This file is part of DevLib ...'
[bertos.git] / drv / timer.h
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2000 Bernardo Innocenti <bernie@develer.com>
31  *
32  * -->
33  *
34  * \version $Id$
35  *
36  * \author Bernardo Innocenti <bernie@develer.com>
37  *
38  * \brief Hardware independent timer driver (interface)
39  */
40
41 /*#*
42  *#* $Log$
43  *#* Revision 1.33  2007/06/07 14:35:12  batt
44  *#* Merge from project_ks.
45  *#*
46  *#* Revision 1.32  2007/01/09 08:57:19  bernie
47  *#* Remove excess parentheses.
48  *#*
49  *#* Revision 1.31  2006/07/19 12:56:26  bernie
50  *#* Convert to new Doxygen style.
51  *#*
52  *#* Revision 1.30  2006/02/24 00:26:49  bernie
53  *#* Fixes for CONFIG_KERNEL.
54  *#*
55  *#* Revision 1.29  2006/02/21 21:28:02  bernie
56  *#* New time handling based on TIMER_TICKS_PER_SEC to support slow timers with ticks longer than 1ms.
57  *#*
58  *#* Revision 1.28  2006/02/17 22:24:21  bernie
59  *#* Update POSIX timer emulator.
60  *#*
61  *#* Revision 1.27  2005/11/27 03:04:19  bernie
62  *#* Move test code to timer_test.c; Add OS_HOSTED support.
63  *#*
64  *#* Revision 1.26  2005/11/04 16:20:02  bernie
65  *#* Fix reference to README.devlib in header.
66  *#*
67  *#* Revision 1.25  2005/07/19 07:26:37  bernie
68  *#* Refactor to decouple timer ticks from milliseconds.
69  *#*
70  *#* Revision 1.24  2005/04/11 19:10:28  bernie
71  *#* Include top-level headers from cfg/ subdir.
72  *#*
73  *#* Revision 1.23  2005/03/01 23:25:46  bernie
74  *#* Move event.h to mware/.
75  *#*
76  *#* Revision 1.22  2004/12/13 12:07:06  bernie
77  *#* DISABLE_IRQSAVE/ENABLE_IRQRESTORE: Convert to IRQ_SAVE_DISABLE/IRQ_RESTORE.
78  *#*
79  *#* Revision 1.21  2004/12/09 08:35:21  bernie
80  *#* Replace IPTR with iptr_t.
81  *#*
82  *#* Revision 1.20  2004/12/08 08:56:41  bernie
83  *#* Rename sigset_t to sigmask_t; Reformat.
84  *#*
85  *#* Revision 1.19  2004/12/08 08:30:37  bernie
86  *#* Convert to mtime_t; timer_minutes(): Remove.
87  *#*
88  *#* Revision 1.18  2004/11/16 23:09:52  bernie
89  *#* Disable timer_minutes() for targets with 16bit time_t.
90  *#*
91  *#* Revision 1.17  2004/11/16 22:37:14  bernie
92  *#* Replace IPTR with iptr_t.
93  *#*
94  *#* Revision 1.16  2004/08/25 14:12:08  rasky
95  *#* Aggiornato il comment block dei log RCS
96  *#*
97  *#* Revision 1.15  2004/08/10 06:59:09  bernie
98  *#* timer_gettick(): Rename to timer_ticks() and add backwards compatibility inline.
99  *#*
100  *#* Revision 1.12  2004/07/30 14:34:10  rasky
101  *#* Vari fix per documentazione e commenti
102  *#* Aggiunte PP_CATn e STATIC_ASSERT
103  *#*
104  *#* Revision 1.11  2004/07/29 22:40:12  bernie
105  *#* Spelling fix.
106  *#*
107  *#* Revision 1.10  2004/07/21 00:13:57  bernie
108  *#* Put timer driver on diet.
109  *#*
110  *#* Revision 1.9  2004/07/20 23:45:01  bernie
111  *#* Finally remove redundant protos.
112  *#*
113  *#* Revision 1.8  2004/07/18 21:57:32  bernie
114  *#* timer_gettick(): Rename to timer_tick() and document better.
115  *#*
116  *#* Revision 1.7  2004/06/27 15:26:17  aleph
117  *#* Declaration fix for build with GCC 3.4
118  *#*
119  *#* Revision 1.6  2004/06/07 18:10:06  aleph
120  *#* Remove free pool of timers; use user-provided Timer structure instead
121  *#*
122  *#* Revision 1.5  2004/06/07 15:57:12  aleph
123  *#* Add function prototypes
124  *#*
125  *#* Revision 1.4  2004/06/06 18:25:44  bernie
126  *#* Rename event macros to look like regular functions.
127  *#*
128  *#* Revision 1.3  2004/06/06 16:57:18  bernie
129  *#* Mark some functions INLINE instead of 'extern inline'.
130  *#*
131  *#* Revision 1.2  2004/06/03 11:27:09  bernie
132  *#* Add dual-license information.
133  *#*
134  *#* Revision 1.1  2004/05/23 18:23:30  bernie
135  *#* Import drv/timer module.
136  *#*
137  *#*/
138 #ifndef DRV_TIMER_H
139 #define DRV_TIMER_H
140
141 #include <cfg/os.h>
142 #include <cfg/cpu.h>
143
144 /*
145  * Include platform-specific binding header if we're hosted.
146  * Try the CPU specific one for bare-metal environments.
147  */
148 #if OS_HOSTED
149         #include OS_HEADER(timer)
150 #else
151         #include CPU_HEADER(timer)
152 #endif
153
154 #include <mware/list.h>
155 #include <cfg/debug.h>
156 #include <cfg/compiler.h>
157 #include <appconfig.h>
158
159
160 extern volatile ticks_t _clock;
161
162 /**
163  * \brief Return the system tick counter (expressed in ticks)
164  *
165  * The result is guaranteed to increment monotonically,
166  * but client code must be tolerant with respect to overflows.
167  *
168  * The following code is safe:
169  *
170  * \code
171  *   ticks_t tea_start_time = timer_clock();
172  *
173  *   boil_water();
174  *
175  *   if (timer_clock() - tea_start_time > TEAPOT_DELAY)
176  *       printf("Your tea, Sir.\n");
177  * \endcode
178  *
179  * \note This function must disable interrupts on 8/16bit CPUs because the
180  * clock variable is larger than the processor word size and can't
181  * be copied atomically.
182  */
183 INLINE ticks_t timer_clock(void)
184 {
185         ticks_t result;
186
187         ATOMIC(result = _clock);
188
189         return result;
190 }
191
192 /**
193  * Faster version of timer_clock(), to be called only when the timer
194  * interrupt is disabled (DISABLE_INTS) or overridden by a
195  * higher-priority or non-nesting interrupt.
196  *
197  * \sa timer_clock
198  */
199 INLINE ticks_t timer_clock_unlocked(void)
200 {
201         return _clock;
202 }
203
204 /** Convert \a ms [ms] to ticks. */
205 INLINE ticks_t ms_to_ticks(mtime_t ms)
206 {
207 #if TIMER_TICKS_PER_SEC < 1000
208         /* Slow timer: avoid rounding down too much. */
209         return (ms * TIMER_TICKS_PER_SEC) / 1000;
210 #else
211         /* Fast timer: don't overflow ticks_t. */
212         return ms * ((TIMER_TICKS_PER_SEC + 500) / 1000);
213 #endif
214 }
215
216 /** Convert \a us [us] to ticks. */
217 INLINE ticks_t us_to_ticks(utime_t us)
218 {
219 #if TIMER_TICKS_PER_SEC < 1000
220         /* Slow timer: avoid rounding down too much. */
221         return ((us / 1000) * TIMER_TICKS_PER_SEC) / 1000;
222 #else
223         /* Fast timer: don't overflow ticks_t. */
224         return (us * ((TIMER_TICKS_PER_SEC + 500) / 1000)) / 1000;
225 #endif
226 }
227
228 /** Convert \a ticks [ticks] to ms. */
229 INLINE mtime_t ticks_to_ms(ticks_t ticks)
230 {
231 #if TIMER_TICKS_PER_SEC < 1000
232         /* Slow timer: avoid rounding down too much. */
233         return (ticks * 1000) / TIMER_TICKS_PER_SEC;
234 #else
235         /* Fast timer: avoid overflowing ticks_t. */
236         return ticks / (TIMER_TICKS_PER_SEC / 1000);
237 #endif
238 }
239
240 /** Convert \a ticks [ticks] to us. */
241 INLINE utime_t ticks_to_us(ticks_t ticks)
242 {
243 #if TIMER_TICKS_PER_SEC < 1000
244         /* Slow timer: avoid rounding down too much. */
245         return ((ticks * 1000) / TIMER_TICKS_PER_SEC) * 1000;
246 #else
247         /* Fast timer: avoid overflowing ticks_t. */
248         return (ticks / (TIMER_TICKS_PER_SEC / 1000)) * 1000;
249 #endif
250 }
251
252 /** Convert \a us [us] to hpticks */
253 INLINE hptime_t us_to_hptime(utime_t us)
254 {
255 #if TIMER_HW_HPTICKS_PER_SEC > 10000000UL
256         return us * ((TIMER_HW_HPTICKS_PER_SEC + 500000UL) / 1000000UL);
257 #else
258         return (us * TIMER_HW_HPTICKS_PER_SEC + 500000UL) / 1000000UL;
259 #endif
260 }
261
262 /** Convert \a hpticks [hptime] to usec */
263 INLINE utime_t hptime_to_us(hptime_t hpticks)
264 {
265 #if TIMER_HW_HPTICKS_PER_SEC < 100000UL
266         return hpticks * (1000000UL / TIMER_HW_HPTICKS_PER_SEC);
267 #else
268         return (hpticks * 1000000UL) / TIMER_HW_HPTICKS_PER_SEC;
269 #endif /* TIMER_HW_HPTICKS_PER_SEC < 100000UL */
270 }
271
272
273 void timer_init(void);
274 void timer_delayTicks(ticks_t delay);
275 INLINE void timer_delay(mtime_t delay)
276 {
277         timer_delayTicks(ms_to_ticks(delay));
278 }
279
280 #if !defined(CONFIG_TIMER_DISABLE_UDELAY)
281 void timer_busyWait(hptime_t delay);
282 void timer_delayHp(hptime_t delay);
283 INLINE void timer_udelay(utime_t delay)
284 {
285         timer_delayHp(us_to_hptime(delay));
286 }
287 #endif
288
289 #ifndef CONFIG_TIMER_DISABLE_EVENTS
290
291 #include <mware/event.h>
292
293 /**
294  * The timer driver supports multiple synchronous timers
295  * that can trigger an event when they expire.
296  *
297  * \sa timer_add()
298  * \sa timer_abort()
299  */
300 typedef struct Timer
301 {
302         Node    link;     /**< Link into timers queue */
303         ticks_t _delay;   /**< Timer delay in ms */
304         ticks_t tick;     /**< Timer will expire at this tick */
305         Event   expire;   /**< Event to execute when the timer expires */
306         DB(uint16_t magic;)
307 } Timer;
308
309 /** Timer is active when Timer.magic contains this value (for debugging purposes). */
310 #define TIMER_MAGIC_ACTIVE    0xABBA
311 #define TIMER_MAGIC_INACTIVE  0xBAAB
312
313 extern void timer_add(Timer *timer);
314 extern Timer *timer_abort(Timer *timer);
315
316 /** Set the timer so that it calls an user hook when it expires */
317 INLINE void timer_set_event_softint(Timer *timer, Hook func, iptr_t user_data)
318 {
319         event_initSoftInt(&timer->expire, func, user_data);
320 }
321
322 /** Set the timer delay (the time before the event will be triggered) */
323 INLINE void timer_setDelay(Timer *timer, ticks_t delay)
324 {
325         timer->_delay = delay;
326 }
327
328 #endif /* CONFIG_TIMER_DISABLE_EVENTS */
329
330 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
331
332 /** Set the timer so that it sends a signal when it expires */
333 INLINE void timer_set_event_signal(Timer *timer, struct Process *proc, sigmask_t sigs)
334 {
335         event_initSignal(&timer->expire, proc, sigs);
336 }
337
338 #endif /* CONFIG_KERN_SIGNALS */
339
340
341 #endif /* DRV_TIMER_H */