altos: Fix up quadrature driver
[fw/altos] / src / drivers / ao_quadrature.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_quadrature.h>
20 #include <ao_exti.h>
21
22 __xdata int32_t ao_quadrature_count;
23
24 static uint8_t  ao_quadrature_state;
25
26 #define BIT(a,b)        ((a) | ((b) << 1))
27 #define STATE(old_a, old_b, new_a, new_b)       (((BIT(old_a, old_b) << 2) | BIT(new_a, new_b)))
28
29 static void
30 ao_quadrature_isr(void)
31 {
32         ao_quadrature_state = ((ao_quadrature_state & 3) << 2);
33         ao_quadrature_state |= ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_A, AO_QUADRATURE_A_PIN);
34         ao_quadrature_state |= ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_B, AO_QUADRATURE_B_PIN) << 1;
35
36         switch (ao_quadrature_state) {
37         case STATE(0, 1, 0, 0):
38                 ao_quadrature_count++;
39                 break;
40         case STATE(1, 0, 0, 0):
41                 ao_quadrature_count--;
42                 break;
43         default:
44                 return;
45         }
46         ao_wakeup(&ao_quadrature_count);
47 }
48
49 int32_t
50 ao_quadrature_poll(void)
51 {
52         int32_t ret;
53         ao_arch_critical(ret = ao_quadrature_count;);
54         return ret;
55 }
56
57 int32_t
58 ao_quadrature_wait(void)
59 {
60         ao_sleep(&ao_quadrature_count);
61         return ao_quadrature_poll();
62 }
63
64 static void
65 ao_quadrature_test(void)
66 {
67 #if 1
68         for (;;) {
69                 int32_t c;
70                 flush();
71                 c = ao_quadrature_wait();
72                 printf ("new count %6d\n", c);
73                 if (c == 100)
74                         break;
75         }
76 #endif
77 #if 0
78         uint8_t a, old_a, b, old_b;
79
80         old_a = 2; old_b = 2;
81         for (;;) {
82                 a = ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_A, AO_QUADRATURE_A_PIN);
83                 b = ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_B, AO_QUADRATURE_B_PIN);
84                 if (a != old_a || b != old_b) {
85                         printf ("A %d B %d count %ld\n", a, b, ao_quadrature_count);
86                         flush();
87                         ao_yield();
88                         old_a = a;
89                         old_b = b;
90                 }
91                 if (ao_stdin_ready)
92                         break;
93         }
94 #endif          
95 }
96
97 static const struct ao_cmds ao_quadrature_cmds[] = {
98         { ao_quadrature_test,   "q\0Test quadrature" },
99         { 0, NULL }
100 };
101
102 void
103 ao_quadrature_init(void)
104 {
105         ao_quadrature_count = 0;
106
107         ao_enable_port(AO_QUADRATURE_PORT);
108         ao_exti_setup(AO_QUADRATURE_PORT, AO_QUADRATURE_A,
109                       AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED,
110                       ao_quadrature_isr);
111         ao_exti_enable(AO_QUADRATURE_PORT, AO_QUADRATURE_A);
112         ao_exti_setup(AO_QUADRATURE_PORT, AO_QUADRATURE_B,
113                       AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED,
114                       ao_quadrature_isr);
115         ao_exti_enable(AO_QUADRATURE_PORT, AO_QUADRATURE_B);
116         ao_cmd_register(&ao_quadrature_cmds[0]);
117 }