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 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 #define MIN_INTER_TIME (50*16)  /* t~=50us dist=350cm */
83 #define MAX_INTER_TIME (2000*16) /* t=2ms dist=20cm */
84
85 /* xmit 2ms after virtual laser: must be < 32768 */
86 #define IR_DELAY (2000*16)
87
88 /* in ms */
89 #define INTER_LASER_TIME 10
90
91 //#define NO_MODULATION
92 #define WAIT_LASER
93
94 /* basic functions to transmit on IR */
95
96 static inline void xmit_0(void)
97 {
98         uint8_t t = ((N_CYCLES_PERIOD * N_PERIODS) / 3);
99 #ifdef NO_MODULATION
100         cbi(IR_PORT, IR_BIT);
101 #else
102         TCCR1B = 0;
103         TCCR1A = 0;
104 #endif
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 #ifdef NO_MODULATION
112         sbi(IR_PORT, IR_BIT);
113 #else
114         TCCR1B = _BV(WGM13) | _BV(WGM12);
115         TCNT1 = N_CYCLES_PERIOD-1;
116         TCCR1A = _BV(COM1A1) | _BV(WGM11);
117         TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
118 #endif
119         _delay_loop_1(t); /* 3 cycles per loop */
120 }
121
122 /* transmit in manchester code */
123
124 static inline void xmit_manchester_0(void)
125 {
126         xmit_0();
127         xmit_1();
128 }
129
130 static inline void xmit_manchester_1(void)
131 {
132         xmit_1();
133         xmit_0();
134 }
135
136 /* transmit a full frame. Each byte is lsb first. */
137
138 static void xmit_bits(uint32_t frame, uint8_t nbit)
139 {
140         uint8_t i;
141
142         for (i=0; i<nbit; i++) {
143                 if (frame & 1)
144                         xmit_manchester_1();
145                 else
146                         xmit_manchester_0();
147
148                 /* next bit */
149                 frame >>= 1UL;
150         }
151         xmit_0();
152 }
153
154 /* Wait 2 consecutive rising edges on photodiode. Return 0 on success,
155  * in this case, the 'when' pointed area is assigned to the time when
156  * IR signal should be sent. */
157 static inline int8_t wait_laser(uint16_t *when)
158 {
159         uint16_t time1, time2;
160         uint16_t diff;
161
162         /* set timer to 16Mhz, we will use ICP */
163         TCCR1A = 0;
164         TCCR1B = _BV(CS10);
165
166         /* wait until all is off */
167         while (READ_PHOTO() != 0);
168         TIFR = _BV(ICF1);
169
170         /* wait rising edge */
171         while ((TIFR & _BV(ICF1)) == 0);
172         time1 = ICR1;
173         TIFR = _BV(ICF1);
174
175         /* wait next rising edge + timeout */
176         while ((TIFR & _BV(ICF1)) == 0) {
177                 diff = TCNT1 - time1;
178                 if (diff > MAX_INTER_TIME)
179                         return -1;
180         }
181
182         time2 = ICR1;
183         TIFR = _BV(ICF1);
184
185         diff = time2 - time1;
186         if (diff < MIN_INTER_TIME)
187                 return -1;
188
189         *when = time1 + (diff/2) + IR_DELAY;
190
191         /* laser ok */
192         return 0;
193 }
194
195 /* */
196
197 int main(void)
198 {
199         /* must be odd */
200         uint32_t frame = FRAME;
201         int8_t ret;
202         uint16_t when = 0;
203
204         /* LEDS */
205         LED_DDR = _BV(LED1_BIT) | _BV(LED2_BIT) | _BV(LED3_BIT);
206         IR_DDR |= _BV(IR_BIT);
207
208         uart_init();
209         fdevopen(uart0_dev_send, uart0_dev_recv);
210         sei();
211
212 #if 0
213         while (1) {
214                 int16_t c;
215                 c = uart_recv_nowait(0);
216                 if (c != -1)
217                         printf("%c", (char)(c+1));
218                 LED1_ON();
219                 wait_ms(500);
220                 LED1_OFF();
221                 wait_ms(500);
222         }
223 #endif
224
225 #if 0
226         while (1) {
227                 if (READ_PHOTO())
228                         LED1_ON();
229                 else
230                         LED1_OFF();
231         }
232 #endif
233
234 #ifndef NO_MODULATION
235         /* configure PWM */
236         ICR1 = N_CYCLES_PERIOD;
237         OCR1A = N_CYCLES_1;
238         TCCR1A = _BV(COM1A1) | _BV(WGM11);
239         TCCR1B = _BV(WGM13) | _BV(WGM12);
240 #endif
241
242         /* configure timer 0, prescaler = 64 */
243         TCCR0 = _BV(CS01) | _BV(CS00);
244
245         while (1) {
246
247 #ifdef WAIT_LASER
248                 ret = wait_laser(&when);
249
250                 LED1_OFF();
251                 LED2_OFF();
252
253                 if (ret)
254                         continue;
255
256                 /* wait before IR xmit */
257                 while ((int16_t)(when-TCNT1) > 0);
258 #endif
259
260 #if 1
261                 LED3_ON();
262                 /* ok, transmit frame */
263                 xmit_bits(frame, FRAME_LEN);
264
265                 /* don't watch a laser during this time */
266                 wait_ms(INTER_LASER_TIME);
267                 LED3_OFF();
268 #else
269                 LED1_ON();
270                 wait_ms(1);
271                 LED1_OFF();
272 #endif
273         }
274         return 0;
275 }