20100416
[aversive.git] / projects / microb2010 / cobboard / sensor.c
1 /*
2  *  Copyright Droids Corporation (2009)
3  *  Olivier MATZ <zer0@droids-corp.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Revision : $Id: sensor.c,v 1.6 2009-11-08 17:25:00 zer0 Exp $
20  *
21  */
22
23 #include <stdlib.h>
24
25 #include <aversive.h>
26 #include <aversive/error.h>
27
28 #include <adc.h>
29 #include <scheduler.h>
30 #include <ax12.h>
31 #include <pwm_ng.h>
32
33 #include <pid.h>
34 #include <quadramp.h>
35 #include <control_system_manager.h>
36 #include <blocking_detection_manager.h>
37
38 #include <parse.h>
39 #include <rdline.h>
40
41 #include "../common/i2c_commands.h"
42 #include "main.h"
43 #include "sensor.h"
44
45 /************ ADC */
46
47 struct adc_infos {
48         uint16_t config;
49         int16_t value;
50         int16_t prev_val;
51         int16_t (*filter)(struct adc_infos *, int16_t);
52 };
53
54 /* reach 90% of the value in 4 samples */
55 int16_t rii_light(struct adc_infos *adc, int16_t val)
56 {
57         adc->prev_val = val + (int32_t)adc->prev_val / 2;
58         return adc->prev_val / 2;
59 }
60
61 /* reach 90% of the value in 8 samples */
62 int16_t rii_medium(struct adc_infos *adc, int16_t val)
63 {
64         adc->prev_val = val + ((int32_t)adc->prev_val * 3) / 4;
65         return adc->prev_val / 4;
66 }
67
68 /* reach 90% of the value in 16 samples */
69 int16_t rii_strong(struct adc_infos *adc, int16_t val)
70 {
71         adc->prev_val = val + ((int32_t)adc->prev_val * 7) / 8;
72         return adc->prev_val / 8;
73 }
74
75
76 #define ADC_CONF(x) ( ADC_REF_AVCC | ADC_MODE_INT | MUX_ADC##x )
77
78 /* define which ADC to poll, see in sensor.h */
79 static struct adc_infos adc_infos[ADC_MAX] = {
80         [ADC_CSENSE1] = { .config = ADC_CONF(0), .filter = rii_medium },
81         [ADC_CSENSE2] = { .config = ADC_CONF(1), .filter = rii_medium },
82         [ADC_CSENSE3] = { .config = ADC_CONF(2), .filter = rii_medium },
83         [ADC_CSENSE4] = { .config = ADC_CONF(3), .filter = rii_medium },
84
85         /* add adc on "cap" pins if needed */
86 /*      [ADC_CAP1] = { .config = ADC_CONF(10) }, */
87 /*      [ADC_CAP2] = { .config = ADC_CONF(11) }, */
88 /*      [ADC_CAP3] = { .config = ADC_CONF(12) }, */
89 /*      [ADC_CAP4] = { .config = ADC_CONF(13) }, */
90 };
91
92 static void adc_event(int16_t result);
93
94 /* called every 10 ms, see init below */
95 static void do_adc(__attribute__((unused)) void *dummy)
96 {
97         /* launch first conversion */
98         adc_launch(adc_infos[0].config);
99 }
100
101 static void adc_event(int16_t result)
102 {
103         static uint8_t i = 0;
104
105         /* filter value if needed */
106         if (adc_infos[i].filter)
107                 adc_infos[i].value = adc_infos[i].filter(&adc_infos[i],
108                                                          result);
109         else
110                 adc_infos[i].value = result;
111
112         i ++;
113         if (i >= ADC_MAX)
114                 i = 0;
115         else
116                 adc_launch(adc_infos[i].config);
117 }
118
119 int16_t sensor_get_adc(uint8_t i)
120 {
121         int16_t tmp;
122         uint8_t flags;
123
124         IRQ_LOCK(flags);
125         tmp = adc_infos[i].value;
126         IRQ_UNLOCK(flags);
127         return tmp;
128 }
129
130 /************ boolean sensors */
131
132
133 struct sensor_filter {
134         uint8_t filter;
135         uint8_t prev;
136         uint8_t thres_off;
137         uint8_t thres_on;
138         uint8_t cpt;
139         uint8_t invert;
140 };
141
142 /* pullup mapping:
143  * CAP 1,5,6,7,8
144  */
145 static struct sensor_filter sensor_filter[SENSOR_MAX] = {
146         [S_COB_INSIDE_L] = { 5, 0, 4, 1, 0, 1 }, /* 0 */
147         [S_CAP2] =      { 10, 0, 3, 7, 0, 0 }, /* 1 */
148         [S_COB_INSIDE_R] = { 5, 0, 4, 1, 0, 0 }, /* 2 */
149         [S_CAP4] =      { 1, 0, 0, 1, 0, 0 }, /* 3 */
150         [S_LCOB] =      { 1, 0, 0, 1, 0, 1 }, /* 4 */
151         [S_LEFT] =      { 5, 0, 4, 1, 0, 0 }, /* 5 */ /////// not used
152         [S_RIGHT] =     { 5, 0, 4, 1, 0, 1 }, /* 6 */ /////// not used
153         [S_RCOB] =      { 1, 0, 0, 1, 0, 1 }, /* 7 */
154         [S_RESERVED1] = { 10, 0, 3, 7, 0, 0 }, /* 8 */
155         [S_RESERVED2] = { 10, 0, 3, 7, 0, 0 }, /* 9 */
156         [S_RESERVED3] = { 1, 0, 0, 1, 0, 0 }, /* 10 */
157         [S_RESERVED4] = { 1, 0, 0, 1, 0, 0 }, /* 11 */
158         [S_RESERVED5] = { 1, 0, 0, 1, 0, 0 }, /* 12 */
159         [S_RESERVED6] = { 1, 0, 0, 1, 0, 0 }, /* 13 */
160         [S_RESERVED7] = { 1, 0, 0, 1, 0, 0 }, /* 14 */
161         [S_RESERVED8] = { 1, 0, 0, 1, 0, 0 }, /* 15 */
162 };
163
164 /* value of filtered sensors */
165 static uint16_t sensor_filtered = 0;
166
167 /* sensor mapping :
168  * 0-3:  PORTK 2->5 (cap1 -> cap4) (adc10 -> adc13)
169  * 4-5:  PORTL 0->1 (cap5 -> cap6)
170  * 6-7:  PORTE 3->4 (cap7 -> cap8)
171  * 8-15: reserved
172  */
173
174 uint16_t sensor_get_all(void)
175 {
176         uint16_t tmp;
177         uint8_t flags;
178         IRQ_LOCK(flags);
179         tmp = sensor_filtered;
180         IRQ_UNLOCK(flags);
181         return tmp;
182 }
183
184 uint8_t sensor_get(uint8_t i)
185 {
186         uint16_t tmp = sensor_get_all();
187         return !!(tmp & _BV(i));
188 }
189
190 /* get the physical value of pins */
191 static uint16_t sensor_read(void)
192 {
193         uint16_t tmp = 0;
194         tmp |= (uint16_t)((PINK & (_BV(2)|_BV(3)|_BV(4)|_BV(5))) >> 2) << 0;
195         tmp |= (uint16_t)((PINL & (_BV(0)|_BV(1))) >> 0) << 4;
196         tmp |= (uint16_t)((PINE & (_BV(3)|_BV(4))) >> 3) << 6;
197         /* add reserved sensors here */
198         return tmp;
199 }
200
201 /* called every 10 ms, see init below */
202 static void do_boolean_sensors(__attribute__((unused)) void *dummy)
203 {
204         uint8_t i;
205         uint8_t flags;
206         uint16_t sensor = sensor_read();
207         uint16_t tmp = 0;
208
209         for (i=0; i<SENSOR_MAX; i++) {
210                 if ((1 << i) & sensor) {
211                         if (sensor_filter[i].cpt < sensor_filter[i].filter)
212                                 sensor_filter[i].cpt++;
213                         if (sensor_filter[i].cpt >= sensor_filter[i].thres_on)
214                                 sensor_filter[i].prev = 1;
215                 }
216                 else {
217                         if (sensor_filter[i].cpt > 0)
218                                 sensor_filter[i].cpt--;
219                         if (sensor_filter[i].cpt <= sensor_filter[i].thres_off)
220                                 sensor_filter[i].prev = 0;
221                 }
222
223                 if (sensor_filter[i].prev && !sensor_filter[i].invert) {
224                         tmp |= (1UL << i);
225                 }
226                 else if (!sensor_filter[i].prev && sensor_filter[i].invert) {
227                         tmp |= (1UL << i);
228                 }
229         }
230         IRQ_LOCK(flags);
231         sensor_filtered = tmp;
232         IRQ_UNLOCK(flags);
233 }
234
235 static uint8_t lcob_cpt = 0, rcob_cpt = 0;
236 uint8_t cob_falling_edge(uint8_t side)
237 {
238         uint8_t flags;
239
240         if (side == I2C_LEFT_SIDE) {
241                 IRQ_LOCK(flags);
242                 if (lcob_cpt == 0) {
243                         IRQ_UNLOCK(flags);
244                         return 0;
245                 }
246                 lcob_cpt = 0;
247                 IRQ_UNLOCK(flags);
248                 return 1;
249         }
250         else {
251                 IRQ_LOCK(flags);
252                 if (rcob_cpt == 0) {
253                         IRQ_UNLOCK(flags);
254                         return 0;
255                 }
256                 rcob_cpt = 0;
257                 IRQ_UNLOCK(flags);
258                 return 1;
259         }
260 }
261
262 static void cob_edge_manage(void)
263 {
264         static uint8_t lprev, rprev;
265         uint8_t l, r;
266         l = sensor_get(S_LCOB);
267         r = sensor_get(S_RCOB);
268         /* falling edge */
269         if (lprev != 0 && l == 0)
270                 lcob_cpt = 10;
271         if (rprev != 0 && r == 0)
272                 rcob_cpt = 10;
273         if (lcob_cpt > 0)
274                 lcob_cpt --;
275         if (rcob_cpt > 0)
276                 rcob_cpt --;
277         lprev = l;
278         rprev = r;
279 }
280
281
282 /************ global sensor init */
283
284 /* called every 10 ms, see init below */
285 static void do_sensors(__attribute__((unused)) void *dummy)
286 {
287         do_adc(NULL);
288         do_boolean_sensors(NULL);
289         cob_edge_manage();
290 }
291
292 void sensor_init(void)
293 {
294         adc_init();
295         adc_register_event(adc_event);
296         /* CS EVENT */
297         scheduler_add_periodical_event_priority(do_sensors, NULL,
298                                                 10000L / SCHEDULER_UNIT,
299                                                 ADC_PRIO);
300 }
301