Save some more RAM on AVR.
[bertos.git] / drv / buzzer.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999, 2003 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \brief Buzzer driver (implementation)
12  *
13  * \version $Id$
14  * \author Bernardo Innocenti <bernie@develer.com>
15  */
16
17 /*#*
18  *#* $Log$
19  *#* Revision 1.10  2004/10/03 18:38:51  bernie
20  *#* Add missing AVR header; Fix header.
21  *#*
22  *#* Revision 1.9  2004/09/14 21:01:25  bernie
23  *#* Use new AVR port pin names.
24  *#*
25  *#* Revision 1.8  2004/08/25 14:12:08  rasky
26  *#* Aggiornato il comment block dei log RCS
27  *#*
28  *#* Revision 1.7  2004/08/24 16:53:43  bernie
29  *#* Add missing headers.
30  *#*
31  *#* Revision 1.6  2004/06/07 18:10:06  aleph
32  *#* Remove free pool of timers; use user-provided Timer structure instead
33  *#*
34  *#* Revision 1.5  2004/06/07 15:54:23  aleph
35  *#* Update to new event.h naming
36  *#*
37  *#* Revision 1.4  2004/06/06 16:09:22  bernie
38  *#* Reformat (from project_ks).
39  *#*
40  *#* Revision 1.3  2004/06/03 11:27:09  bernie
41  *#* Add dual-license information.
42  *#*
43  *#* Revision 1.2  2004/05/23 18:21:53  bernie
44  *#* Trim CVS logs and cleanup header info.
45  *#*
46  *#*/
47
48 #include "buzzer.h"
49
50 #include <drv/timer.h>
51 #include <kern/event.h>
52 #include <debug.h>
53 #include <hw.h>
54 #include <arch_config.h>
55
56
57 #if (ARCH & ARCH_EMUL)
58
59         int Emul_IsBuzzerOn(void);
60         void Emul_BuzzerOn(void);
61         void Emul_BuzzerOff(void);
62         void Emul_BuzzerInit(void);
63
64         #define IS_BUZZER_ON  (Emul_IsBuzzerOn())
65         #define BUZZER_ON     (Emul_BuzzerOn())
66         #define BUZZER_OFF    (Emul_BuzzerOff())
67         #define BUZZER_INIT   (Emul_BuzzerInit())
68
69 #elif defined(__AVR__)
70
71         #include <avr/io.h>
72
73         #define IS_BUZZER_ON  (PORTG & BV(PG0))
74
75         /*!
76          * Buzzer manipulation macros
77          *
78          * \note Some PORTG functions are being used from
79          *       interrupt code, so we must be careful to
80          *       avoid race conditions.
81          */
82         #define BUZZER_ON \
83         do { \
84                 cpuflags_t _flags; \
85                 DISABLE_IRQSAVE(_flags); \
86                 PORTG |= BV(PG0); \
87                 ENABLE_IRQRESTORE(_flags); \
88         } while (0)
89
90         #define BUZZER_OFF \
91         do { \
92                 cpuflags_t _flags; \
93                 DISABLE_IRQSAVE(_flags); \
94                 PORTG &= ~BV(PG0); \
95                 ENABLE_IRQRESTORE(_flags); \
96         } while (0)
97
98         #define BUZZER_INIT \
99         do { \
100                 cpuflags_t _flags; \
101                 DISABLE_IRQSAVE(_flags); \
102                 PORTG &= ~BV(PG0); \
103                 DDRG |= BV(PG0); \
104                 ENABLE_IRQRESTORE(_flags); \
105         } while (0)
106
107 #elif defined(__IAR_SYSTEMS_ICC) || defined(__IAR_SYSTEMS_ICC__) /* 80C196 */
108
109         #define IS_BUZZER_ON  (cpld->Buzzer & 1)
110         #define BUZZER_ON     (cpld->Buzzer = 1)
111         #define BUZZER_OFF    (cpld->Buzzer = 0)
112         #define BUZZER_INIT   (cpld->Buzzer = 0)
113
114 #endif /* ARCH, __AVR__, __IAR_SYSTEM_ICC */
115
116
117 /* Local vars */
118 static Timer buz_timer;
119 static bool buz_timer_running;
120 static time_t buz_repeat_interval;
121 static time_t buz_repeat_duration;
122
123
124 /*!
125  * Turn off buzzer, called by software timer
126  */
127 static void buz_softint(void)
128 {
129         if (IS_BUZZER_ON)
130         {
131                 BUZZER_OFF;
132                 if (buz_repeat_interval)
133                 {
134                         /* Wait for interval time */
135                         buz_timer.delay = buz_repeat_interval;
136                         timer_add(&buz_timer);
137                 }
138                 else
139                         buz_timer_running = false;
140         }
141         else if (buz_repeat_interval)
142         {
143                 /* Wait for beep time */
144                 BUZZER_ON;
145                 buz_timer.delay = buz_repeat_duration;
146                 timer_add(&buz_timer);
147         }
148         else
149                 buz_timer_running = false;
150 }
151
152
153 /*!
154  * Beep for the specified ms time
155  */
156 void buz_beep(time_t time)
157 {
158         cpuflags_t flags;
159
160         /* Remove the software interrupt if it was already queued */
161         DISABLE_IRQSAVE(flags);
162         if (buz_timer_running)
163                 timer_abort(&buz_timer);
164
165         /* Turn on buzzer */
166         BUZZER_ON;
167
168         /* Add software interrupt to turn the buzzer off later */
169         buz_timer_running = true;
170         buz_timer.delay = time;
171         timer_add(&buz_timer);
172
173         ENABLE_IRQRESTORE(flags);
174 }
175
176
177 /*!
178  * Start buzzer repetition
179  */
180 void buz_repeat_start(time_t duration, time_t interval)
181 {
182         buz_repeat_interval = interval;
183         buz_repeat_duration = duration;
184         buz_beep(duration);
185 }
186
187
188 /*!
189  * Stop buzzer repetition
190  */
191 void buz_repeat_stop(void)
192 {
193         cpuflags_t flags;
194         DISABLE_IRQSAVE(flags);
195
196         /* Remove the software interrupt if it was already queued */
197         if (buz_timer_running)
198         {
199                 timer_abort(&buz_timer);
200                 buz_timer_running = false;
201         }
202
203         buz_repeat_interval = 0;
204         BUZZER_OFF;
205
206         ENABLE_IRQRESTORE(flags);
207 }
208
209
210 /*!
211  * Initialize buzzer
212  */
213 void buz_init(void)
214 {
215         BUZZER_INIT;
216
217         /* Inizializza software interrupt */
218         event_initSoftInt(&buz_timer.expire, (Hook)buz_softint, 0);
219 }