Merge improvements from kseries (mainly inlining)
[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  * \author Bernardo Innocenti <bernie@develer.com>
12  *
13  * \brief Buzzer driver
14  */
15
16 /*
17  * $Log$
18  * Revision 1.3  2004/06/03 11:27:09  bernie
19  * Add dual-license information.
20  *
21  * Revision 1.2  2004/05/23 18:21:53  bernie
22  * Trim CVS logs and cleanup header info.
23  *
24  */
25
26 #include "hw.h"
27 #include "kdebug.h"
28 #include "timer.h"
29 #include "buzzer.h"
30 #include <kern/event.h>
31
32
33 #if (ARCH & ARCH_EMUL)
34
35         int Emul_IsBuzzerOn(void);
36         void Emul_BuzzerOn(void);
37         void Emul_BuzzerOff(void);
38         void Emul_BuzzerInit(void);
39
40 #       define IS_BUZZER_ON  (Emul_IsBuzzerOn())
41 #       define BUZZER_ON     (Emul_BuzzerOn())
42 #       define BUZZER_OFF    (Emul_BuzzerOff())
43 #       define BUZZER_INIT   (Emul_BuzzerInit())
44
45 #elif defined(__AVR__)
46
47 #       define IS_BUZZER_ON  (PORTG & BV(PORTG0))
48
49         /**
50          * Buzzer manipulation macros
51          *
52          * \note Some PORTG functions are being used from
53          *       interrupt code, so we must be careful to
54          *       avoid race conditions.
55          */
56 #       define BUZZER_ON \
57         do { \
58                 cpuflags_t _flags; \
59                 DISABLE_IRQSAVE(_flags); \
60                 PORTG |= BV(PORTG0); \
61                 ENABLE_IRQRESTORE(_flags); \
62         } while (0)
63
64 #       define BUZZER_OFF \
65         do { \
66                 cpuflags_t _flags; \
67                 DISABLE_IRQSAVE(_flags); \
68                 PORTG &= ~BV(PORTG0); \
69                 ENABLE_IRQRESTORE(_flags); \
70         } while (0)
71
72 #       define BUZZER_INIT \
73         do { \
74                 cpuflags_t _flags; \
75                 DISABLE_IRQSAVE(_flags); \
76                 PORTG &= ~BV(PORTG0); \
77                 DDRG |= BV(PORTG0); \
78                 ENABLE_IRQRESTORE(_flags); \
79         } while (0)
80
81 #elif defined(__IAR_SYSTEMS_ICC) || defined(__IAR_SYSTEMS_ICC__) /* 80C196 */
82
83 #       define IS_BUZZER_ON  (cpld->Buzzer & 1)
84 #       define BUZZER_ON     (cpld->Buzzer = 1)
85 #       define BUZZER_OFF    (cpld->Buzzer = 0)
86 #       define BUZZER_INIT   (cpld->Buzzer = 0)
87
88 #endif /* ARCH, __AVR__, __IAR_SYSTEM_ICC */
89
90
91 /* Local vars */
92 static Timer *buz_timer;
93 static bool buz_timer_running;
94 static time_t buz_repeat_interval;
95 static time_t buz_repeat_duration;
96
97
98 /*!
99  * Turn off buzzer, called by software timer
100  */
101 static void buz_softint(void)
102 {
103         if (IS_BUZZER_ON)
104         {
105                 BUZZER_OFF;
106                 if (buz_repeat_interval)
107                 {
108                         /* Wait for interval time */
109                         buz_timer->delay = buz_repeat_interval;
110                         timer_add(buz_timer);
111                 }
112                 else
113                         buz_timer_running = false;
114         }
115         else if (buz_repeat_interval)
116         {
117                 /* Wait for beep time */
118                 BUZZER_ON;
119                 buz_timer->delay = buz_repeat_duration;
120                 timer_add(buz_timer);
121         }
122         else
123                 buz_timer_running = false;
124 }
125
126
127 /*!
128  * Beep for the specified ms time
129  */
130 void buz_beep(time_t time)
131 {
132         cpuflags_t flags;
133
134         /* Remove the software interrupt if it was already queued */
135         DISABLE_IRQSAVE(flags);
136         if (buz_timer_running)
137                 timer_abort(buz_timer);
138
139         /* Turn on buzzer */
140         BUZZER_ON;
141
142         /* Add software interrupt to turn the buzzer off later */
143         buz_timer_running = true;
144         buz_timer->delay = time;
145         timer_add(buz_timer);
146
147         ENABLE_IRQRESTORE(flags);
148 }
149
150
151 /*!
152  * Start buzzer repetition
153  */
154 void buz_repeat_start(time_t duration, time_t interval)
155 {
156         buz_repeat_interval = interval;
157         buz_repeat_duration = duration;
158         buz_beep(duration);
159 }
160
161
162 /*!
163  * Stop buzzer repetition
164  */
165 void buz_repeat_stop(void)
166 {
167         cpuflags_t flags;
168         DISABLE_IRQSAVE(flags);
169
170         /* Remove the software interrupt if it was already queued */
171         if (buz_timer_running)
172         {
173                 timer_abort(buz_timer);
174                 buz_timer_running = false;
175         }
176
177         buz_repeat_interval = 0;
178         BUZZER_OFF;
179
180         ENABLE_IRQRESTORE(flags);
181 }
182
183
184 /*!
185  * Initialize buzzer
186  */
187 void buz_init(void)
188 {
189         BUZZER_INIT;
190
191         /* Inizializza software interrupt */
192         buz_timer = timer_new();
193         ASSERT(buz_timer != NULL);
194         INITEVENT_INT(&buz_timer->expire, (Hook)buz_softint, 0);
195 }