beacon
[aversive.git] / projects / microb2010 / tests / static_beacon / static_beacon.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: main.c,v 1.8 2009-05-02 10:08:09 zer0 Exp $
20  *
21  */
22
23 #include <math.h>
24
25 #include <aversive.h>
26 #include <aversive/wait.h>
27 #include <aversive/pgmspace.h>
28
29 #include <uart.h>
30
31 /*
32  * Leds: PD5 -> PD7
33  * Photodiodes: PC0 PC1
34  * IR: PB1, OC1A
35  */
36
37 /*
38  * hfuse:  RSTDISBL=1 WTDON=1 SPIEN=0 CKOPT=0 EESAVE=1 BOOTSZ1=0 BOOTSZ0=0 BOOTRST=1
39  * lfuse:  BODLEVEL=1 BODEN=1 SUT1=1 SUT0=1 CKSEL3=1 CKSEL2=1 CKSEL1=1 CKSEL0=1
40  */
41
42 //#define NO_MODULATION
43 #define WAIT_LASER
44 #define MODUL_455KHZ
45 //#define MODUL_56KHZ
46 //#define MODUL_38KHZ
47 //#define SPEED_40RPS
48 #define SPEED_20RPS
49 //#define SPEED_10RPS
50
51 /* beacon identifier: must be odd, 3 bits */
52 #define BEACON_ID 0x1
53 #define BEACON_ID_MASK 0x7
54 #define BEACON_ID_SHIFT 0
55
56 /* */
57 #define FRAME_DATA_MASK  0x0FF8
58 #define FRAME_DATA_SHIFT 3
59
60 #if (defined MODUL_455KHZ)
61 #define N_PERIODS   15
62 #define N_CYCLES_0  17
63 #define N_CYCLES_1  17
64 #elif (defined MODUL_56KHZ)
65 #define N_PERIODS   15
66 #define N_CYCLES_0  143
67 #define N_CYCLES_1  143
68 #elif (defined MODUL_38KHZ)
69 #define N_PERIODS   15
70 #define N_CYCLES_0  210
71 #define N_CYCLES_1  210
72 #else
73 #error "no freq defined"
74 #endif
75
76 #define MIN_DIST 150.
77 #define MAX_DIST 3600.
78 #define LASER_DIST 25.
79
80 #define N_CYCLES_PERIOD (N_CYCLES_0 + N_CYCLES_1)
81
82 #define LED_PORT PORTD
83 #define LED_DDR  DDRD
84 #define LED1_BIT  5
85 #define LED2_BIT  6
86 #define LED3_BIT  7
87
88 #define LED_TOGGLE(port, bit) do {              \
89           if (port & _BV(bit))                  \
90                   port &= ~_BV(bit);            \
91           else                                  \
92                   port |= _BV(bit);             \
93   } while(0)
94
95 #define LED1_ON()  sbi(LED_PORT, LED1_BIT)
96 #define LED1_OFF() cbi(LED_PORT, LED1_BIT)
97 #define LED1_TOGGLE() LED_TOGGLE(LED_PORT, LED1_BIT)
98 #define LED2_ON()  sbi(LED_PORT, LED2_BIT)
99 #define LED2_OFF() cbi(LED_PORT, LED2_BIT)
100 #define LED2_TOGGLE() LED_TOGGLE(LED_PORT, LED2_BIT)
101 #define LED3_ON()  sbi(LED_PORT, LED3_BIT)
102 #define LED3_OFF() cbi(LED_PORT, LED3_BIT)
103 #define LED3_TOGGLE() LED_TOGGLE(LED_PORT, LED3_BIT)
104
105 #define IR_PORT PORTB
106 #define IR_DDR  DDRB
107 #define IR_BIT  1
108
109 /* FRAME must be odd */
110 /* #define FRAME 0x0B /\* in little endian 1-1-0-1 *\/ */
111 /* #define FRAME_LEN 4 */
112 #define FRAME 0x4A5B /* in little endian */
113 #define FRAME_LEN 16
114
115 /* pin returns !0 when nothing, and 0 when laser is on photodiode */
116 #define PHOTO_PIN PINB
117 #define PHOTO_BIT 0
118 #define READ_PHOTO() (!!(PHOTO_PIN & (_BV(PHOTO_BIT))))
119
120 /* IR_DELAY **must** be < 32768 */
121 #if (defined SPEED_10RPS)
122 #define MIN_INTER_TIME    ((uint16_t)(160*2))  /* t~=160us dist=350cm */
123 #define MAX_INTER_TIME    ((uint16_t)(8000*2)) /* t=8ms dist=10cm */
124 #define IR_DELAY          ((uint16_t)(8000*2))
125 #define INTER_LASER_TIME   30 /* in ms */
126 #elif (defined SPEED_20RPS)
127 #define MIN_INTER_TIME    ((uint16_t)(40*16))   /* t~=80us dist=350cm */
128 #define MAX_INTER_TIME    ((uint16_t)(2000*16)) /* t=2ms dist=? >10cm */
129 #define IR_DELAY          ((uint16_t)(2000*16))
130 #define INTER_LASER_TIME   10 /* in ms */
131 #elif (defined SPEED_40RPS)
132 #define MIN_INTER_TIME    ((uint16_t)(40*16))  /* t~=40us dist=350cm */
133 #define MAX_INTER_TIME    ((uint16_t)(2000*16)) /* t=2ms dist=10cm */
134 #define IR_DELAY          ((uint16_t)(2000*16))
135 #define INTER_LASER_TIME   10 /* in ms */
136 #else
137 #error "speed not defined"
138 #endif
139
140 extern prog_uint16_t framedist_table[];
141 /* basic functions to transmit on IR */
142
143 static inline void xmit_0(void)
144 {
145         uint16_t t = ((N_CYCLES_PERIOD * N_PERIODS) / 4);
146 #ifdef NO_MODULATION
147         cbi(IR_PORT, IR_BIT);
148 #else
149         TCCR1B = 0;
150         TCCR1A = 0;
151 #endif
152         _delay_loop_2(t); /* 4 cycles per loop */
153 }
154
155 static inline void xmit_1(void)
156 {
157         uint16_t t = ((N_CYCLES_PERIOD * N_PERIODS) / 4);
158 #ifdef NO_MODULATION
159         sbi(IR_PORT, IR_BIT);
160 #else
161         TCCR1B = _BV(WGM13) | _BV(WGM12);
162         TCNT1 = N_CYCLES_PERIOD-1;
163         TCCR1A = _BV(COM1A1) | _BV(WGM11);
164         ICR1 = N_CYCLES_PERIOD;
165         TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
166 #endif
167         _delay_loop_2(t); /* 4 cycles per loop */
168 }
169
170 /* transmit in manchester code */
171
172 static inline void xmit_manchester_0(void)
173 {
174         xmit_0();
175         xmit_1();
176 }
177
178 static inline void xmit_manchester_1(void)
179 {
180         xmit_1();
181         xmit_0();
182 }
183
184 /* transmit a full frame. Each byte is lsb first. */
185
186 static void xmit_bits(uint32_t frame, uint8_t nbit)
187 {
188         uint8_t i;
189
190         for (i=0; i<nbit; i++) {
191                 if (frame & 1)
192                         xmit_manchester_1();
193                 else
194                         xmit_manchester_0();
195
196                 /* next bit */
197                 frame >>= 1UL;
198         }
199         xmit_0();
200 }
201
202 #ifdef WAIT_LASER
203 /* val is 12 bits. Return the 16 bits value that includes the 4 bits
204  * cksum in MSB. */
205 static uint16_t do_cksum(uint16_t val)
206 {
207         uint16_t x, cksum;
208
209         x = (val & 0xfff);
210         /* add the three 4-bits blocks of x together */
211         cksum = x & 0xf;
212         x = x >> 4;
213         cksum += x & 0xf;
214         cksum = (cksum & 0xf) + ((cksum & 0xf0) >> 4);
215         x = x >> 4;
216         cksum += x & 0xf;
217         cksum = (cksum & 0xf) + ((cksum & 0xf0) >> 4);
218         cksum = (~cksum) & 0xf;
219         return (cksum << 12) + (val & 0xfff);
220 }
221
222 /* get the frame from laser time difference, return 0 on error (this
223  * frame cannot be sent). */
224 static uint32_t get_frame(uint16_t laserdiff)
225 {
226         uint32_t frame = 0;
227         uint16_t frame_dist = 256;
228         uint16_t step, val;
229
230         /* for calibration, return the time */
231         if (0)
232                 return laserdiff;
233
234         for (step = 128; step != 0; step /= 2) {
235                 val = pgm_read_word(&framedist_table[frame_dist]);
236                 if (laserdiff > val)
237                         frame_dist -= step;
238                 else
239                         frame_dist += step;
240         }
241
242         frame |= ((uint32_t)(frame_dist & FRAME_DATA_MASK) << FRAME_DATA_SHIFT);
243
244         /* process cksum and return */
245         return do_cksum(frame);
246 }
247
248 /* Wait 2 consecutive rising edges on photodiode. Return 0 on success,
249  * in this case, the 'when' pointed area is assigned to the time when
250  * IR signal should be sent. The 'laserdiff' pointer is the time
251  * between the 2 lasers, in timer unit. */
252 static inline int8_t wait_laser(uint16_t *when, uint16_t *laserdiff)
253 {
254         uint16_t time1, time2;
255         uint16_t diff;
256
257 #if (defined SPEED_40RPS) || (defined SPEED_20RPS)
258         /* set timer to 16Mhz, we will use ICP */
259         TCCR1A = 0;
260         TCCR1B = _BV(CS10);
261 #else /* 10 RPS */
262         /* set timer to 2Mhz, we will use ICP */
263         TCCR1A = 0;
264         TCCR1B = _BV(CS11);
265 #endif
266
267         /* wait until all is off (inverted logic)  */
268         while (READ_PHOTO() == 0);
269         TIFR = _BV(ICF1);
270
271         /* wait falling edge */
272         while ((TIFR & _BV(ICF1)) == 0);
273         time1 = ICR1;
274
275         LED1_ON();
276
277         /* wait a bit to avoid oscillations */
278         while ((uint16_t)(TCNT1-time1) < MIN_INTER_TIME);
279         TIFR = _BV(ICF1);
280
281         /* wait next falling edge + timeout */
282         while ((TIFR & _BV(ICF1)) == 0) {
283                 diff = TCNT1 - time1;
284                 if (diff > MAX_INTER_TIME)
285                         return -1;
286         }
287
288         LED2_ON();
289
290         /* get time of 2nd laser */
291         time2 = ICR1;
292         TIFR = _BV(ICF1);
293
294         /* process time difference */
295         diff = time2 - time1;
296         if (diff < MIN_INTER_TIME)
297                 return -1;
298
299         *when = time1 + (diff/2) + IR_DELAY;
300         *laserdiff = diff;
301
302         /* laser ok */
303         return 0;
304 }
305 #endif
306
307 /* */
308
309 int main(void)
310 {
311         /* must be odd */
312         uint32_t frame = FRAME;
313 #ifdef WAIT_LASER
314         int8_t ret;
315         uint16_t when = 0;
316         uint16_t diff = 0;
317 #endif
318         /* LEDS */
319         LED_DDR = _BV(LED1_BIT) | _BV(LED2_BIT) | _BV(LED3_BIT);
320         IR_DDR |= _BV(IR_BIT);
321
322         uart_init();
323         fdevopen(uart0_dev_send, uart0_dev_recv);
324         sei();
325
326 #if 0
327         while (1) {
328                 int16_t c;
329                 c = uart_recv_nowait(0);
330                 if (c != -1)
331                         printf("%c", (char)(c+1));
332                 LED1_ON();
333                 wait_ms(500);
334                 LED1_OFF();
335                 wait_ms(500);
336         }
337 #endif
338
339 #if 0
340         while (1) {
341                 if (READ_PHOTO())
342                         LED1_ON();
343                 else
344                         LED1_OFF();
345         }
346 #endif
347
348 #ifndef NO_MODULATION
349         /* configure PWM */
350         ICR1 = N_CYCLES_PERIOD;
351         OCR1A = N_CYCLES_1;
352         TCCR1A = _BV(COM1A1) | _BV(WGM11);
353         TCCR1B = _BV(WGM13) | _BV(WGM12);
354 #endif
355
356 #if 0
357         /* test freq */
358         ICR1 = N_CYCLES_PERIOD;
359         OCR1A = N_CYCLES_1;
360         TCCR1B = _BV(WGM13) | _BV(WGM12);
361         TCNT1 = N_CYCLES_PERIOD-1;
362         TCCR1A = _BV(COM1A1) | _BV(WGM11);
363         TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
364         while (1);
365 #endif
366
367 #if 0
368         /* test freq ~ 400khz */
369         ICR1 = 38;
370         OCR1A = 19;
371         TCCR1B = _BV(WGM13) | _BV(WGM12);
372         TCNT1 = 37;
373         TCCR1A = _BV(COM1A1) | _BV(WGM11);
374         TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
375
376         /* motor PWM 50%, 8khz */
377         DDRB |= 0x08;
378         OCR2 = 50;
379         TCCR2 = _BV(WGM21) | _BV(WGM20) | _BV(COM21) | _BV(CS21) ;
380         
381         while (1);
382 #endif
383
384
385         /* configure timer 0, prescaler = 64 */
386         TCCR0 = _BV(CS01) | _BV(CS00);
387
388         while (1) {
389
390 #ifdef WAIT_LASER
391                 ret = wait_laser(&when, &diff);
392
393                 LED1_OFF();
394                 LED2_OFF();
395
396                 if (ret)
397                         continue;
398
399                 frame = get_frame(diff);
400                 /* cannot convert into frame... skip it */
401                 if (frame == 0) {
402                         wait_ms(INTER_LASER_TIME);
403                         continue;
404                 }
405
406                 /* wait before IR xmit */
407                 while ((int16_t)(when-TCNT1) > 0);
408 #endif
409
410                 LED3_ON();
411                 /* ok, transmit frame */
412                 xmit_bits(frame, FRAME_LEN);
413
414                 LED3_OFF();
415
416                 /* don't watch a laser during this time */
417                 wait_ms(INTER_LASER_TIME);
418         }
419         return 0;
420 }