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