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