25c0cd5cea66b753813cd566102ce5ba6f7c9da9
[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         ao_debounce_config(debounce,
78                            _ao_button_get,
79                            _ao_button_set,
80                            AO_BUTTON_DEBOUNCE_HOLD);
81 }
82
83 static void
84 ao_button_isr(void)
85 {
86         uint8_t b;
87
88         for (b = 0; b < AO_BUTTON_COUNT; b++)
89                 _ao_debounce_start(&ao_button_debounce[b]);
90 }
91
92 #define init(b) do {                                                    \
93                 ao_button_debounce_init(&ao_button_debounce[b]);        \
94                 ao_enable_port(port(b));                                \
95                                                                         \
96                 ao_exti_setup(port(b), bit(b),                          \
97                               AO_BUTTON_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
98                               ao_button_isr);                   \
99                 ao_exti_enable(port(b), bit(b));                        \
100         } while (0)
101
102 void
103 ao_button_init(void)
104 {
105 #if AO_BUTTON_COUNT > 0
106         init(0);
107 #endif
108 #if AO_BUTTON_COUNT > 1
109         init(1);
110 #endif
111 #if AO_BUTTON_COUNT > 2
112         init(2);
113 #endif
114 #if AO_BUTTON_COUNT > 3
115         init(3);
116 #endif
117 #if AO_BUTTON_COUNT > 4
118         init(4);
119 #endif
120         ao_debounce_init();
121 }