work on 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 N_PERIODS   10
40 #define N_CYCLES_0  17
41 #define N_CYCLES_1  17
42 #define N_CYCLES_PERIOD (N_CYCLES_0 + N_CYCLES_1)
43
44 #define LED_PORT PORTD
45 #define LED_DDR  DDRD
46 #define LED1_BIT  5
47 #define LED2_BIT  6
48 #define LED3_BIT  7
49
50 #define LED_TOGGLE(port, bit) do {              \
51                 if (port & _BV(bit))            \
52                         port &= ~_BV(bit);      \
53                 else                            \
54                         port |= _BV(bit);       \
55         } while(0)
56
57 #define LED1_ON()  sbi(LED_PORT, LED1_BIT)
58 #define LED1_OFF() cbi(LED_PORT, LED1_BIT)
59 #define LED1_TOGGLE() LED_TOGGLE(LED_PORT, LED1_BIT)
60 #define LED2_ON()  sbi(LED_PORT, LED2_BIT)
61 #define LED2_OFF() cbi(LED_PORT, LED2_BIT)
62 #define LED2_TOGGLE() LED_TOGGLE(LED_PORT, LED2_BIT)
63 #define LED3_ON()  sbi(LED_PORT, LED3_BIT)
64 #define LED3_OFF() cbi(LED_PORT, LED3_BIT)
65 #define LED3_TOGGLE() LED_TOGGLE(LED_PORT, LED3_BIT)
66
67 #define IR_PORT PORTB
68 #define IR_DDR  DDRB
69 #define IR_BIT  1
70
71 /* FRAME must be odd */
72 /* #define FRAME 0x0B /\* in little endian 1-1-0-1 *\/ */
73 /* #define FRAME_LEN 4 */
74 #define FRAME 0xAA5B /* in little endian */
75 #define FRAME_LEN 16
76
77 /* pin returns 1 when nothing, and 0 when laser is on photodiode */
78 #define PHOTO_PIN PINC
79 #define PHOTO1_BIT 0
80 #define PHOTO2_BIT 1
81 #define READ_PHOTOS() (PHOTO_PIN & (_BV(PHOTO1_BIT) | _BV(PHOTO2_BIT)))
82 #define READ_PHOTO1() (PHOTO_PIN & _BV(PHOTO1_BIT))
83 #define READ_PHOTO2() (PHOTO_PIN & _BV(PHOTO2_BIT))
84
85 #define PHOTOS_ALL_OFF (_BV(PHOTO1_BIT) | _BV(PHOTO2_BIT))
86 #define PHOTOS_ALL_ON (0)
87 #define PHOTOS_1ON_2OFF (_BV(PHOTO2_BIT))
88 #define PHOTOS_1OFF_2ON (_BV(PHOTO1_BIT))
89
90
91 /* in cycles/64 (unit is 4 us at 16Mhz) */
92 #define MAX_PHOTO_TIME ((uint8_t)25)  /* t=100us len=5mm rps=40Hz dist=20cm */
93
94 #define MIN_INTER_TIME ((uint8_t)12)  /* t=50us len=50mm rps=40Hz dist=350cm */
95 #define MAX_INTER_TIME ((uint8_t)250) /* t=1000us len=50mm rps=40Hz dist=20cm */
96
97 /* in ms */
98 #define INTER_LASER_TIME 10
99
100 #define NO_MODULATION
101 //#define WAIT_LASER
102
103 /* basic functions to transmit on IR */
104
105 static inline void xmit_0(void)
106 {
107         uint8_t t = ((N_CYCLES_PERIOD * N_PERIODS) / 3);
108 #ifdef NO_MODULATION
109         cbi(IR_PORT, IR_BIT);
110 #else
111         TCCR1B = 0;
112         TCCR1A = 0;
113 #endif
114         _delay_loop_1(t); /* 3 cycles per loop */
115 }
116
117 static inline void xmit_1(void)
118 {
119         uint8_t t = ((N_CYCLES_PERIOD * N_PERIODS) / 3);
120 #ifdef NO_MODULATION
121         sbi(IR_PORT, IR_BIT);
122 #else
123         TCCR1B = _BV(WGM13) | _BV(WGM12);
124         TCNT1 = N_CYCLES_PERIOD-1;
125         TCCR1A = _BV(COM1A1) | _BV(WGM11);
126         TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
127 #endif
128         _delay_loop_1(t); /* 3 cycles per loop */
129 }
130
131 /* transmit in manchester code */
132
133 static inline void xmit_manchester_0(void)
134 {
135         xmit_0();
136         xmit_1();
137 }
138
139 static inline void xmit_manchester_1(void)
140 {
141         xmit_1();
142         xmit_0();
143 }
144
145 /* transmit a full frame. Each byte is lsb first. */
146
147 static void xmit_bits(uint32_t frame, uint8_t nbit)
148 {
149         uint8_t i;
150
151         for (i=0; i<nbit; i++) {
152                 if (frame & 1)
153                         xmit_manchester_1();
154                 else
155                         xmit_manchester_0();
156
157                 /* next bit */
158                 frame >>= 1UL;
159         }
160         xmit_0();
161 }
162
163 /* */
164 static inline int8_t wait_laser(void)
165 {
166         uint8_t photos;
167         uint8_t time;
168         uint8_t diff;
169
170         /* wait until all is off */
171         while (READ_PHOTOS() != PHOTOS_ALL_OFF);
172
173         /* wait an event, it must be photo1 on */
174         while ((photos = READ_PHOTOS()) == PHOTOS_ALL_OFF);
175
176         if (photos != PHOTOS_1ON_2OFF)
177                 return -1;
178         time = TCNT0;
179         LED1_ON();
180
181         /* wait an event, it must be photo1 off */
182         while ((photos = READ_PHOTOS()) == PHOTOS_1ON_2OFF) {
183                 diff = TCNT0 - time;
184                 if (diff > MAX_PHOTO_TIME)
185                         return -1;
186         }
187         if (photos != PHOTOS_ALL_OFF)
188                 return -1;
189         //time = TCNT0;
190
191         /* wait an event, it must be photo2 on */
192         while ((photos = READ_PHOTOS()) == PHOTOS_ALL_OFF) {
193                 diff = TCNT0 - time;
194                 if (diff > MAX_INTER_TIME)
195                         return -1;
196         }
197         LED2_ON();
198         
199         diff = TCNT0 - time;
200         if (diff < MIN_INTER_TIME)
201                 return -1;
202         if (photos != PHOTOS_1OFF_2ON)
203                 return -1;
204
205 #if 0   
206         time = TCNT0;
207
208         /* wait an event, it must be photo2 off */
209         while ((photos = READ_PHOTOS()) == PHOTOS_1OFF_2ON) {
210                 diff = TCNT0 - time;
211                 if (diff > MAX_PHOTO_TIME)
212                         return -1;
213         }
214         if (photos != PHOTOS_ALL_OFF)
215                 return -1;
216 #endif
217
218         /* laser ok */
219         return 0;
220 }
221
222 /* */
223
224 int main(void)
225 {
226         /* must be odd */
227         uint32_t frame = FRAME;
228         int8_t ret;
229         int16_t c;
230
231         /* LEDS */
232         LED_DDR = _BV(LED1_BIT) | _BV(LED2_BIT) | _BV(LED3_BIT);
233         IR_DDR |= _BV(IR_BIT);
234
235         uart_init();
236         fdevopen(uart0_dev_send, uart0_dev_recv);
237         sei();
238
239 #if 0
240         while (1) {
241                 c = uart_recv_nowait(0);
242                 if (c != -1) 
243                         printf("%c", (char)(c+1));
244                 LED1_ON();
245                 wait_ms(500);
246                 LED1_OFF();
247                 wait_ms(500);
248         }
249 #endif
250
251 #if 0
252         while (1) {
253                 if (READ_PHOTO() & _BV(PHOTO1_BIT))
254                         LED1_ON();
255                 else
256                         LED1_OFF();
257         }
258 #endif
259
260 #ifndef NO_MODULATION
261         /* configure PWM */
262         ICR1 = N_CYCLES_PERIOD;
263         OCR1A = N_CYCLES_1;
264         TCCR1A = _BV(COM1A1) | _BV(WGM11);
265         TCCR1B = _BV(WGM13) | _BV(WGM12);
266 #endif
267
268         /* configure timer 0, prescaler = 64 */
269         TCCR0 = _BV(CS01) | _BV(CS00);
270
271         while (1) {
272
273 #ifdef WAIT_LASER
274                 ret = wait_laser();
275                 
276                 LED1_OFF();
277                 LED2_OFF();
278
279                 if (ret)
280                         continue;
281 #endif
282                 
283 #if 1
284                 LED3_ON();
285                 /* ok, transmit frame */
286                 xmit_bits(frame, FRAME_LEN);
287                 
288                 /* don't watch a laser during this time */
289                 wait_ms(INTER_LASER_TIME);
290                 LED3_OFF();
291 #else
292                 LED1_ON();
293                 wait_ms(1);
294                 LED1_OFF();
295 #endif
296         }
297         return 0;
298 }