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