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