vt100: include pgmspace.h as we use PROGMEM macro
[aversive.git] / projects / microb2010 / tests / test_board2008 / 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-05-02 10:08:09 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 <pwm_ng.h>
31
32 #include <pid.h>
33 #include <quadramp.h>
34 #include <control_system_manager.h>
35 #include <trajectory_manager.h>
36 #include <blocking_detection_manager.h>
37 #include <robot_system.h>
38 #include <position_manager.h>
39
40 #include <parse.h>
41 #include <rdline.h>
42
43 #include "main.h"
44 #include "sensor.h"
45
46 /************ ADC */
47
48 struct adc_infos {
49         uint16_t config;
50         int16_t value;
51         int16_t prev_val;
52         int16_t (*filter)(struct adc_infos *, int16_t);
53 };
54
55 /* reach 90% of the value in 4 samples */
56 int16_t rii_light(struct adc_infos *adc, int16_t val)
57 {
58         adc->prev_val = val + (int32_t)adc->prev_val / 2;
59         return adc->prev_val / 2;
60 }
61
62 /* reach 90% of the value in 8 samples */
63 int16_t rii_medium(struct adc_infos *adc, int16_t val)
64 {
65         adc->prev_val = val + ((int32_t)adc->prev_val * 3) / 4;
66         return adc->prev_val / 4;
67 }
68
69 /* reach 90% of the value in 16 samples */
70 int16_t rii_strong(struct adc_infos *adc, int16_t val)
71 {
72         adc->prev_val = val + ((int32_t)adc->prev_val * 7) / 8;
73         return adc->prev_val / 8;
74 }
75
76
77 #define ADC_CONF(x) ( ADC_REF_AVCC | ADC_MODE_INT | MUX_ADC##x )
78
79 /* define which ADC to poll, see in sensor.h */
80 static struct adc_infos adc_infos[ADC_MAX] = { 
81         [ADC_CSENSE1] = { .config = ADC_CONF(0), .filter = rii_medium },
82         [ADC_CSENSE2] = { .config = ADC_CONF(1), .filter = rii_medium },
83         [ADC_CSENSE3] = { .config = ADC_CONF(2), .filter = rii_medium },
84         [ADC_CSENSE4] = { .config = ADC_CONF(3), .filter = rii_medium },
85 /*      [ADC_BATTERY1] = { .config = ADC_CONF(8), .filter = rii_strong }, */
86 /*      [ADC_BATTERY2] = { .config = ADC_CONF(9), .filter = rii_strong }, */
87
88         /* add adc on "cap" pins if needed */
89 /*      [ADC_CAP1] = { .config = ADC_CONF(10) }, */
90 /*      [ADC_CAP2] = { .config = ADC_CONF(11) }, */
91 /*      [ADC_CAP3] = { .config = ADC_CONF(12) }, */
92 /*      [ADC_CAP4] = { .config = ADC_CONF(13) }, */
93 };
94
95 static void adc_event(int16_t result);
96
97 /* called every 10 ms, see init below */
98 static void do_adc(void *dummy) 
99 {
100         /* launch first conversion */
101         adc_launch(adc_infos[0].config);
102 }
103
104 static void adc_event(int16_t result)
105 {
106         static uint8_t i = 0;
107
108         /* filter value if needed */
109         if (adc_infos[i].filter)
110                 adc_infos[i].value = adc_infos[i].filter(&adc_infos[i],
111                                                          result);
112         else
113                 adc_infos[i].value = result;
114
115         i ++;
116         if (i >= ADC_MAX)
117                 i = 0;
118         else
119                 adc_launch(adc_infos[i].config);
120 }
121
122 int16_t sensor_get_adc(uint8_t i)
123 {
124         int16_t tmp;
125         uint8_t flags;
126
127         IRQ_LOCK(flags);
128         tmp = adc_infos[i].value;
129         IRQ_UNLOCK(flags);
130         return tmp;
131 }
132
133 /************ boolean sensors */
134
135
136 struct sensor_filter {
137         uint8_t filter;
138         uint8_t prev;
139         uint8_t thres_off;
140         uint8_t thres_on;
141         uint8_t cpt;
142         uint8_t invert;
143 };
144
145 /* pullup mapping:
146  * CAP 1,5,6,7,8
147  */
148 static struct sensor_filter sensor_filter[SENSOR_MAX] = {
149         [S_CAP1] = { 1, 0, 0, 1, 0, 0 }, /* 4 */
150         [S_CAP2] = { 1, 0, 0, 1, 0, 0 }, /* 1 */
151         [S_COLUMN_LEFT] = { 1, 0, 0, 1, 0, 1 }, /* 2 */
152         [S_COLUMN_RIGHT] = { 1, 0, 0, 1, 0, 1 }, /* 3 */
153         [S_START_SWITCH] = { 10, 0, 3, 7, 0, 0 }, /* 0 */
154         [S_DISP_LEFT] = { 1, 0, 0, 1, 0, 1 }, /* 5 */
155         [S_DISP_RIGHT] = { 1, 0, 0, 1, 0, 1 }, /* 6 */
156         [S_CAP8] = { 1, 0, 0, 1, 0, 0 }, /* 7 */
157         [S_RESERVED1] = { 10, 0, 3, 7, 0, 0 }, /* 8 */
158         [S_RESERVED2] = { 10, 0, 3, 7, 0, 0 }, /* 9 */
159         [S_RESERVED3] = { 1, 0, 0, 1, 0, 0 }, /* 10 */
160         [S_RESERVED4] = { 1, 0, 0, 1, 0, 0 }, /* 11 */
161         [S_RESERVED5] = { 1, 0, 0, 1, 0, 0 }, /* 12 */
162         [S_RESERVED6] = { 1, 0, 0, 1, 0, 0 }, /* 13 */
163         [S_RESERVED7] = { 1, 0, 0, 1, 0, 0 }, /* 14 */
164         [S_RESERVED8] = { 1, 0, 0, 1, 0, 0 }, /* 15 */
165 };
166
167 /* value of filtered sensors */
168 static uint16_t sensor_filtered = 0;
169
170 /* sensor mapping : 
171  * 0-3:  PORTK 2->5 (cap1 -> cap4) (adc10 -> adc13)
172  * 4-5:  PORTL 0->1 (cap5 -> cap6)
173  * 6-7:  PORTE 3->4 (cap7 -> cap8)
174  * 8-15: reserved
175  */
176
177 uint16_t sensor_get_all(void)
178 {
179         uint16_t tmp;
180         uint8_t flags;
181         IRQ_LOCK(flags);
182         tmp = sensor_filtered;
183         IRQ_UNLOCK(flags);
184         return tmp;
185 }
186
187 uint8_t sensor_get(uint8_t i)
188 {
189         uint16_t tmp = sensor_get_all();
190         return (tmp & _BV(i));
191 }
192
193 /* get the physical value of pins */
194 static uint16_t sensor_read(void)
195 {
196         uint16_t tmp = 0;
197         tmp |= ((PINE & _BV(5)) >> 5);
198
199 /*      tmp |= (uint16_t)((PINK & (_BV(2)|_BV(3)|_BV(4)|_BV(5))) >> 2) << 0; */
200 /*      tmp |= (uint16_t)((PINL & (_BV(0)|_BV(1))) >> 0) << 4; */
201 /*      tmp |= (uint16_t)((PINE & (_BV(3)|_BV(4))) >> 3) << 6; */
202         /* add reserved sensors here */
203         return tmp;
204 }
205
206 /* called every 10 ms, see init below */
207 static void do_boolean_sensors(void *dummy)
208 {
209         uint8_t i;
210         uint8_t flags;
211         uint16_t sensor = sensor_read();
212         uint16_t tmp = 0;
213
214         for (i=0; i<SENSOR_MAX; i++) {
215                 if ((1 << i) & sensor) {
216                         if (sensor_filter[i].cpt < sensor_filter[i].filter)
217                                 sensor_filter[i].cpt++;
218                         if (sensor_filter[i].cpt >= sensor_filter[i].thres_on)
219                                 sensor_filter[i].prev = 1;
220                 }
221                 else {
222                         if (sensor_filter[i].cpt > 0)
223                                 sensor_filter[i].cpt--;
224                         if (sensor_filter[i].cpt <= sensor_filter[i].thres_off)
225                                 sensor_filter[i].prev = 0;
226                 }
227                 
228                 if (sensor_filter[i].prev) {
229                         tmp |= (1UL << i);
230                 }
231         }
232         IRQ_LOCK(flags);
233         sensor_filtered = tmp;
234         IRQ_UNLOCK(flags);
235 }
236
237 /* virtual obstacle */
238
239 #define DISABLE_CPT_MAX 200
240 static uint8_t disable = 0; /* used to disable obstacle detection 
241                            * during some time */
242
243 /* called every 10 ms */
244 void
245 sensor_obstacle_update(void)
246 {
247         if (disable > 0) {
248                 disable --;
249                 if (disable == 0)
250                         DEBUG(E_USER_STRAT, "re-enable sensor");
251         }
252 }
253
254 void sensor_obstacle_disable(void)
255 {
256         DEBUG(E_USER_STRAT, "disable sensor");
257         disable = DISABLE_CPT_MAX;
258 }
259
260 void sensor_obstacle_enable(void)
261 {
262         disable = 0;
263 }
264
265 uint8_t sensor_obstacle_is_disabled(void)
266 {
267         return disable;
268 }
269
270
271 /************ global sensor init */
272
273 /* called every 10 ms, see init below */
274 static void do_sensors(void *dummy)
275 {
276         do_adc(NULL);
277         do_boolean_sensors(NULL);
278         sensor_obstacle_update();
279 }
280
281 void sensor_init(void)
282 {
283         adc_init();
284         adc_register_event(adc_event);
285         /* CS EVENT */
286         scheduler_add_periodical_event_priority(do_sensors, NULL, 
287                                                 10000L / SCHEDULER_UNIT, 
288                                                 ADC_PRIO);
289 }
290