7b1fb530c7d11c32d5d7d48dd37eddf3fadb50ea
[fw/altos] / src / drivers / ao_button.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_button.h>
20 #include <ao_exti.h>
21 #include <ao_debounce.h>
22 #if AO_EVENT
23 #include <ao_event.h>
24 #define ao_button_queue(b,v)    ao_event_put_isr(AO_EVENT_BUTTON, b, v)
25 #else
26 #define ao_button_queue(b,v)
27 #endif
28
29 #define AO_BUTTON_DEBOUNCE_HOLD 10
30
31 static struct ao_debounce       ao_button_debounce[AO_BUTTON_COUNT];
32
33 #define port(q) AO_BUTTON_ ## q ## _PORT
34 #define bit(q) AO_BUTTON_ ## q
35 #define pin(q) AO_BUTTON_ ## q ## _PIN
36
37 /* pins are inverted */
38 #define ao_button_value(b)      !ao_gpio_get(port(b), bit(b), pin(b))
39
40 static uint8_t
41 _ao_button_get(struct ao_debounce *debounce)
42 {
43         uint8_t b = debounce - ao_button_debounce;
44
45         switch (b) {
46 #if AO_BUTTON_COUNT > 0
47         case 0: return ao_button_value(0);
48 #endif
49 #if AO_BUTTON_COUNT > 1
50         case 1: return ao_button_value(1);
51 #endif
52 #if AO_BUTTON_COUNT > 2
53         case 2: return ao_button_value(2);
54 #endif
55 #if AO_BUTTON_COUNT > 3
56         case 3: return ao_button_value(3);
57 #endif
58 #if AO_BUTTON_COUNT > 4
59         case 4: return ao_button_value(4);
60 #endif
61         }
62 }
63
64 static void
65 _ao_button_set(struct ao_debounce *debounce, uint8_t value)
66 {
67         uint8_t b = debounce - ao_button_debounce;
68
69         ao_button_queue(b, value);
70 }
71
72
73 #define ao_button_update(b)     ao_button_do(b, ao_gpio_get(port(b), bit(b), pin(b)))
74
75 static void
76 ao_button_debounce_init(struct ao_debounce *debounce) {
77         debounce->hold = AO_BUTTON_DEBOUNCE_HOLD;
78         debounce->_get = _ao_button_get;
79         debounce->_set = _ao_button_set;
80 }
81
82 static void
83 ao_button_isr(void)
84 {
85         uint8_t b;
86
87         for (b = 0; b < AO_BUTTON_COUNT; b++)
88                 _ao_debounce_start(&ao_button_debounce[b]);
89 }
90
91 #define init(b) do {                                                    \
92                 ao_button_debounce_init(&ao_button_debounce[b]);        \
93                 ao_enable_port(port(b));                                \
94                                                                         \
95                 ao_exti_setup(port(b), bit(b),                          \
96                               AO_BUTTON_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
97                               ao_button_isr);                   \
98                 ao_exti_enable(port(b), bit(b));                        \
99         } while (0)
100
101 void
102 ao_button_init(void)
103 {
104 #if AO_BUTTON_COUNT > 0
105         init(0);
106 #endif
107 #if AO_BUTTON_COUNT > 1
108         init(1);
109 #endif
110 #if AO_BUTTON_COUNT > 2
111         init(2);
112 #endif
113 #if AO_BUTTON_COUNT > 3
114         init(3);
115 #endif
116 #if AO_BUTTON_COUNT > 4
117         init(4);
118 #endif
119         ao_debounce_init();
120 }