2 * Copyright Droids Corporation (2009)
3 * Olivier MATZ <zer0@droids-corp.org>
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.
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.
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
19 * Revision : $Id: sensor.c,v 1.3 2009-05-27 20:04:07 zer0 Exp $
26 #include <aversive/error.h>
29 #include <scheduler.h>
35 #include <control_system_manager.h>
36 #include <blocking_detection_manager.h>
43 #include "../common/i2c_commands.h"
51 int16_t (*filter)(struct adc_infos *, int16_t);
54 /* reach 90% of the value in 4 samples */
55 int16_t rii_light(struct adc_infos *adc, int16_t val)
57 adc->prev_val = val + (int32_t)adc->prev_val / 2;
58 return adc->prev_val / 2;
61 /* reach 90% of the value in 8 samples */
62 int16_t rii_medium(struct adc_infos *adc, int16_t val)
64 adc->prev_val = val + ((int32_t)adc->prev_val * 3) / 4;
65 return adc->prev_val / 4;
68 /* reach 90% of the value in 16 samples */
69 int16_t rii_strong(struct adc_infos *adc, int16_t val)
71 adc->prev_val = val + ((int32_t)adc->prev_val * 7) / 8;
72 return adc->prev_val / 8;
76 #define ADC_CONF(x) ( ADC_REF_AVCC | ADC_MODE_INT | MUX_ADC##x )
78 /* define which ADC to poll, see in sensor.h */
79 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 },
86 /* add adc on "cap" pins if needed */
87 /* [ADC_CAP1] = { .config = ADC_CONF(10) }, */
88 /* [ADC_CAP2] = { .config = ADC_CONF(11) }, */
89 /* [ADC_CAP3] = { .config = ADC_CONF(12) }, */
90 /* [ADC_CAP4] = { .config = ADC_CONF(13) }, */
93 static void adc_event(int16_t result);
95 /* called every 10 ms, see init below */
96 static void do_adc(void *dummy)
98 /* launch first conversion */
99 adc_launch(adc_infos[0].config);
102 static void adc_event(int16_t result)
104 static uint8_t i = 0;
106 /* filter value if needed */
107 if (adc_infos[i].filter)
108 adc_infos[i].value = adc_infos[i].filter(&adc_infos[i],
111 adc_infos[i].value = result;
117 adc_launch(adc_infos[i].config);
120 int16_t sensor_get_adc(uint8_t i)
126 tmp = adc_infos[i].value;
131 /************ boolean sensors */
134 struct sensor_filter {
145 * voltage div mapping:
148 static struct sensor_filter sensor_filter[SENSOR_MAX] = {
149 [S_HIGH_BARRIER] = { 20, 0, 1, 19, 0, 1 }, /* 0 */
150 [S_LOW_BARRIER] = { 50, 0, 1, 1, 0, 0 }, /* 1 */
151 [S_CAP3] = { 1, 0, 0, 1, 0, 0 }, /* 2 */
152 [S_CAP4] = { 1, 0, 0, 1, 0, 0 }, /* 3 */
153 [S_R_IR] = { 1, 0, 0, 1, 0, 0 }, /* 4 */
154 [S_R_US] = { 1, 0, 0, 1, 0, 1 }, /* 5 */
155 [S_L_US] = { 1, 0, 0, 1, 0, 1 }, /* 6 */
156 [S_L_IR] = { 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 */
167 /* value of filtered sensors */
168 static uint16_t sensor_filtered = 0;
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)
177 uint16_t sensor_get_all(void)
182 tmp = sensor_filtered;
187 uint8_t sensor_get(uint8_t i)
189 uint16_t tmp = sensor_get_all();
190 return !!(tmp & _BV(i));
193 /* get the physical value of pins */
194 static uint16_t sensor_read(void)
197 tmp |= (uint16_t)((PINK & (_BV(2)|_BV(3)|_BV(4)|_BV(5))) >> 2) << 0;
198 tmp |= (uint16_t)((PINL & (_BV(0)|_BV(1))) >> 0) << 4;
199 tmp |= (uint16_t)((PINE & (_BV(3)|_BV(4))) >> 3) << 6;
200 /* add reserved sensors here */
204 /* called every 10 ms, see init below */
205 static void do_boolean_sensors(void *dummy)
209 uint16_t sensor = sensor_read();
212 for (i=0; i<SENSOR_MAX; i++) {
213 if ((1 << i) & sensor) {
214 if (sensor_filter[i].cpt < sensor_filter[i].filter)
215 sensor_filter[i].cpt++;
216 if (sensor_filter[i].cpt >= sensor_filter[i].thres_on)
217 sensor_filter[i].prev = 1;
220 if (sensor_filter[i].cpt > 0)
221 sensor_filter[i].cpt--;
222 if (sensor_filter[i].cpt <= sensor_filter[i].thres_off)
223 sensor_filter[i].prev = 0;
226 if (sensor_filter[i].prev && !sensor_filter[i].invert) {
229 else if (!sensor_filter[i].prev && sensor_filter[i].invert) {
234 sensor_filtered = tmp;
238 static volatile uint8_t lcob_seen = I2C_COB_NONE;
239 static volatile uint8_t rcob_seen = I2C_COB_NONE;
241 uint8_t cob_detect_left(void)
247 lcob_seen = I2C_COB_NONE;
252 uint8_t cob_detect_right(void)
258 rcob_seen = I2C_COB_NONE;
263 #define COB_MIN_DETECT 4
264 #define COB_MAX_DETECT 50
265 static void do_cob_detection(void)
268 uint16_t tmp = sensor_get_all();
269 uint8_t l_us = !!(tmp & _BV(S_L_US));
270 uint8_t r_us = !!(tmp & _BV(S_R_US));
271 uint8_t l_ir = !!(tmp & _BV(S_L_IR));
272 uint8_t r_ir = !!(tmp & _BV(S_R_IR));
273 static uint8_t l_us_prev, r_us_prev, l_ir_prev, r_ir_prev;
274 static uint8_t l_cpt_on, l_cpt_off;
275 static uint8_t r_cpt_on, r_cpt_off;
277 /* rising edge on US */
278 if (l_us_prev == 0 && l_us == 1) {
285 if (l_ir && l_cpt_on < COB_MAX_DETECT)
287 else if (l_cpt_off < COB_MAX_DETECT)
291 /* falling edge on US */
292 if (l_us_prev == 1 && l_us == 0) {
293 /* detection should not be too short or too long */
294 if ((l_cpt_off + l_cpt_on) < COB_MAX_DETECT &&
295 (l_cpt_off + l_cpt_on) > COB_MIN_DETECT) {
297 if (l_cpt_on > l_cpt_off)
298 lcob_seen = I2C_COB_WHITE;
300 lcob_seen = I2C_COB_BLACK;
302 if (l_cpt_on > l_cpt_off)
303 DEBUG(E_USER_SENSOR, "left white %d %d",
304 l_cpt_on, l_cpt_off);
306 DEBUG(E_USER_SENSOR, "left black %d %d",
307 l_cpt_on, l_cpt_off);
312 /* rising edge on US */
313 if (r_us_prev == 0 && r_us == 1) {
320 if (r_ir && r_cpt_on < COB_MAX_DETECT)
322 else if (r_cpt_off < COB_MAX_DETECT)
326 /* falling edge on US */
327 if (r_us_prev == 1 && r_us == 0) {
329 /* detection should not be too short or too long */
330 if ((r_cpt_off + r_cpt_on) < COB_MAX_DETECT &&
331 (r_cpt_off + r_cpt_on) > COB_MIN_DETECT) {
333 if (r_cpt_on > r_cpt_off)
334 rcob_seen = I2C_COB_WHITE;
336 rcob_seen = I2C_COB_BLACK;
339 if (r_cpt_on > r_cpt_off)
340 DEBUG(E_USER_SENSOR, "right white %d %d",
341 r_cpt_on, r_cpt_off);
343 DEBUG(E_USER_SENSOR, "right black %d %d",
344 r_cpt_on, r_cpt_off);
355 /************ global sensor init */
356 #define BACKGROUND_ADC 0
358 /* called every 10 ms, see init below */
359 static void do_sensors(void *dummy)
363 do_boolean_sensors(NULL);
367 void sensor_init(void)
371 adc_register_event(adc_event);
373 scheduler_add_periodical_event_priority(do_sensors, NULL,
374 10000L / SCHEDULER_UNIT,