]> git.gag.com Git - fw/altos/blob - src/cc1111/ao_button.c
0496a32f270454b95935017896c318eec98482bc
[fw/altos] / src / cc1111 / ao_button.c
1 /*
2  * Copyright © 2011 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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 volatile __xdata struct ao_fifo ao_button_fifo;
22
23 static __code struct {
24         uint8_t mask;
25         uint8_t reg;
26 } ao_buttons[] = {
27 #ifdef BUTTON_1_MASK
28         { BUTTON_1_MASK, BUTTON_1_REG },
29 #endif
30 #ifdef BUTTON_2_MASK
31         { BUTTON_2_MASK, BUTTON_2_REG },
32 #endif
33 #ifdef BUTTON_3_MASK
34         { BUTTON_3_MASK, BUTTON_3_REG },
35 #endif
36 };
37
38 #define NUM_BUTTONS     ((sizeof ao_buttons) / sizeof (ao_buttons[0]))
39
40 static __xdata uint16_t ao_button_tick[NUM_BUTTONS];
41
42 static void
43 ao_button_insert(char n)
44 {
45         uint16_t        now = ao_time();
46         if ((now - ao_button_tick[n]) > 20) {
47                 ao_button_tick[n] = now;
48                 ao_fifo_insert(ao_button_fifo, n);
49                 ao_wakeup(&ao_button_fifo);
50         }
51 }
52
53 static void
54 ao_button_isr(uint8_t flag, uint8_t reg)
55 {
56         uint8_t b;
57
58         for (b = 0; b < NUM_BUTTONS; b++)
59                 if (ao_buttons[b].reg == reg && (ao_buttons[b].mask & flag))
60                         ao_button_insert(b + 1);
61 }
62
63 static uint8_t
64 ao_button_mask(uint8_t reg)
65 {
66         uint8_t b;
67         uint8_t mask = 0;
68
69         for (b = 0; b < NUM_BUTTONS; b++)
70                 if (ao_buttons[b].reg == reg)
71                         mask |= ao_buttons[b].mask;
72         return mask;
73 }
74
75 char
76 ao_button_get(uint16_t timeout) __critical
77 {
78         char    b;
79
80         while (ao_fifo_empty(ao_button_fifo))
81                 if (ao_sleep_for(&ao_button_fifo, timeout))
82                         return 0;
83         ao_fifo_remove(ao_button_fifo, b);
84         return b;
85 }
86
87 void
88 ao_button_clear(void) __critical
89 {
90         char b;
91
92         while (!ao_fifo_empty(ao_button_fifo))
93                 ao_fifo_remove(ao_button_fifo, b);
94 }
95
96 void
97 ao_p0_isr(void) ao_arch_interrupt(13)
98 {
99         P0IF = 0;
100         ao_button_isr(P0IFG, 0);
101         P0IFG = 0;
102 }
103
104 void
105 ao_p1_isr(void) ao_arch_interrupt(15)
106 {
107         P1IF = 0;
108         ao_button_isr(P1IFG, 1);
109         P1IFG = 0;
110 }
111
112 /* Shared with USB */
113 void
114 ao_p2_isr(void)
115 {
116         ao_button_isr(P2IFG, 2);
117         P2IFG = 0;
118 }
119
120 void
121 ao_button_init(void)
122 {
123         uint8_t mask;
124
125         /* Pins are configured as inputs with pull-up by default */
126
127         /* Enable interrupts for P0 inputs */
128         mask = ao_button_mask(0);
129         if (mask) {
130                 if (mask & 0x0f)
131                         PICTL |= PICTL_P0IENL;
132                 if (mask & 0xf0)
133                         PICTL |= PICTL_P0IENH;
134                 P0IFG = 0;
135                 P0IF = 0;
136                 IEN1 |= IEN1_P0IE;
137                 PICTL |= PICTL_P0ICON;
138         }
139
140         /* Enable interrupts for P1 inputs */
141         mask = ao_button_mask(1);
142         if (mask) {
143                 P1IEN |= mask;
144                 P1IFG = 0;
145                 P1IF = 0;
146                 IEN2 |= IEN2_P1IE;
147                 PICTL |= PICTL_P1ICON;
148         }
149
150         /* Enable interrupts for P2 inputs */
151         mask = ao_button_mask(2);
152         if (mask) {
153                 PICTL |= PICTL_P2IEN;
154                 P2IFG = 0;
155                 P2IF = 0;
156                 IEN2 |= IEN2_P2IE;
157                 PICTL |= PICTL_P2ICON;
158         }
159 }