cdf073524e1e8f4ffb5f232f255c5ef854de28fe
[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         return 0;
63 }
64
65 static void
66 _ao_button_set(struct ao_debounce *debounce, uint8_t value)
67 {
68         uint8_t b = debounce - ao_button_debounce;
69
70         ao_button_queue(b, value);
71 }
72
73
74 #define ao_button_update(b)     ao_button_do(b, ao_gpio_get(port(b), bit(b), pin(b)))
75
76 static void
77 ao_button_debounce_init(struct ao_debounce *debounce) {
78         ao_debounce_config(debounce,
79                            _ao_button_get,
80                            _ao_button_set,
81                            AO_BUTTON_DEBOUNCE_HOLD);
82 }
83
84 static void
85 ao_button_isr(void)
86 {
87         uint8_t b;
88
89         for (b = 0; b < AO_BUTTON_COUNT; b++)
90                 _ao_debounce_start(&ao_button_debounce[b]);
91 }
92
93 #define init(b) do {                                                    \
94                 ao_button_debounce_init(&ao_button_debounce[b]);        \
95                 ao_enable_port(port(b));                                \
96                                                                         \
97                 ao_exti_setup(port(b), bit(b),                          \
98                               AO_BUTTON_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
99                               ao_button_isr);                   \
100                 ao_exti_enable(port(b), bit(b));                        \
101         } while (0)
102
103 void
104 ao_button_init(void)
105 {
106 #if AO_BUTTON_COUNT > 0
107         init(0);
108 #endif
109 #if AO_BUTTON_COUNT > 1
110         init(1);
111 #endif
112 #if AO_BUTTON_COUNT > 2
113         init(2);
114 #endif
115 #if AO_BUTTON_COUNT > 3
116         init(3);
117 #endif
118 #if AO_BUTTON_COUNT > 4
119         init(4);
120 #endif
121         ao_debounce_init();
122 }