Updated FSF address in all files. Fixes ticket:51
[debian/gnuradio] / ezdop / src / firmware / dopctrl.c
1 /*
2  * AE6HO EZ-Doppler firmware for onboard ATmega8 microcontroller
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /*
24  * ARCHITECTURE
25  * 
26  * Timer0 is 8000 Hz time base
27  * PORTD.2 through PORTD.5 are doppler antenna array element enables.
28  * PORTB.0 is a diagnostic LED, set low to light up
29  * ADC7 is audio input
30  * ADC6 is RSSI input - not yet used
31  *
32  */
33
34 #include <avr/io.h>
35 #include <avr/interrupt.h>
36 #include <avr/signal.h>
37 #include "dopctrl.h"
38
39 #define LED 0
40 #define turn_off_led()  PORTB |= _BV(LED);
41 #define turn_on_led()   PORTB &= ~_BV(LED);
42
43 #define ANT1 _BV(2)
44 #define ANT2 _BV(3)
45 #define ANT3 _BV(4)
46 #define ANT4 _BV(5)
47 #define ANTMASK ANT1|ANT2|ANT3|ANT4
48
49 #define ADCAIN 7
50 #define BAUDRATE 250000
51
52 /* Assume these are all set to zero in startup code */
53
54 uint8_t rotate;         /* Flag to indicate antennas should rotate or not */
55 uint8_t streaming;      /* Flag to indicate continuous sampling */
56 uint8_t antennas;       /* Holds shadow copy of PORTD antennas */
57 uint8_t speed;          /* Holds samples per phase increment */
58 uint8_t phase;          /* Holds rotation phase (measured in samples */
59
60 uint8_t audio_hi;       /* High byte of ADC sample of audio */
61 uint8_t audio_lo;       /* Low byte of ADC sample of audio */
62
63 uint8_t rx;             /* Temporary holds received byte from USART */
64 uint8_t command;        /* Temporary to hold command when getting operand */
65 uint8_t cmdbyte;        /* Tracks bytes received in multi-byte commands */
66
67 int main(void)
68 {
69         /* Diagnostic port setup */
70         DDRB = _BV(LED);                                                /* PB0 is output */
71         turn_off_led();
72         
73         /* Antenna control port setup */
74         speed = 4;                                                      /* Todo: read from EEPROM */
75         antennas = ANT1;                                        /* Start with antenna #1 */
76         PORTD = antennas;                                       /* Set port value */
77         DDRD = ANTMASK;                                         /* Set antenna enables as PORTD outputs */
78         
79         /* ADC port setup */
80         ADMUX = _BV(REFS0)|ADCAIN;                      /* AVCC is reference, use ADC for audio input (ADC7) */
81         ADCSRA = _BV(ADEN)|_BV(ADIE)|0x07; /* Enable converter, prescale by 128, enable ADC interrupt */
82         
83         /* USART port setup*/
84         UCSRA = 0;                                                      /* Normal asynchronous mode */
85         UCSRB = _BV(TXEN)|_BV(RXEN)|_BV(RXCIE); /* Enable transmitter and receiver, and receiver interrupts */
86         UCSRC = _BV(URSEL)|_BV(UCSZ1)|_BV(UCSZ0); /* 8N1 format */
87         UBRRH = 0;                                                      /* Set baud rate prescaler to 3 */
88         UBRRL = 3;                                                      /* To get 250000 bps */
89         
90         /* Set up 8000 Hz time base */
91         timer_enable_int(_BV(TOIE0));           /* Turn on Timer0 output overflow interrupt */
92         TCCR0 = _BV(CS01);                                      /* Clock Timer0 from CLK/8 */
93         
94         sei();                                                          /* Let 'er rip! */
95         return 0;
96 }
97
98 /* Timer0 overflow interrupt handler
99  *
100  * Creates 8000 Hz time base, or 125us budget
101  *
102  */
103 SIGNAL(SIG_OVERFLOW0)
104 {
105         /* Reload Timer0 samples to 8, results in 8000 Hz overflow interrupt */
106         TCNT0 = 0x08;
107
108         if (streaming) {
109                 /* Kick-off an audio sample conversion, will interrupt 104us later */
110                 ADCSRA |= _BV(ADSC);
111
112                 /* Write the first byte of previous sample and enable UDRIE */
113                 UDR = audio_lo;
114                 UCSRB |= _BV(UDRIE);
115         }
116
117         if (!rotate)    /* Skip rotating antenna if not started */
118                 return;
119
120         /* Increment antenna phase and see if antenna need to be rotated */
121     if (++phase == speed) {
122                 phase = 0;
123                 
124                 /* Sequence antenna array elements */
125                 antennas >>= 1;
126                 antennas &= ANTMASK;
127
128                 if (!antennas)
129                         antennas = ANT4;
130                 PORTD = antennas;
131         }
132 }
133
134 /* ADC conversion complete interrupt handler
135  *
136  * Read value and store. Assume prior sample has been handled.
137  *
138  */
139 SIGNAL(SIG_ADC)
140 {
141         audio_lo = ADCL;
142         audio_hi = ADCH;
143 }
144
145 /* USART data transmit holding register empty interrupt handler
146  * 
147  * First byte is always sent from timer interrupt
148  * So second byte gets sent here with UDRIE disabled
149  *
150  */
151 SIGNAL(SIG_UART_DATA)
152 {
153         /* Write second byte of previous sample and disable UDRIE */
154         UDR = audio_hi | (antennas << 2);
155         UCSRB &= ~_BV(UDRIE);
156 }
157
158 /* USART receive complete interrupt handler
159  *
160  * Received bytes are commands, with one or two bytes of operands following
161  *
162  */
163 SIGNAL(SIG_UART_RECV)
164 {
165         rx = UDR;
166
167         if (cmdbyte == 0) {
168                 if (rx == EZDOP_CMD_ROTATE)             /* Start rotation */
169                         rotate = 1;
170                 else if (rx == EZDOP_CMD_STOP)       /* Stop rotation */
171                         rotate = 0;
172         else if (rx == EZDOP_CMD_RATE) {     /* Set rotation rate */
173             command = rx;
174             cmdbyte = 1;
175         }
176         else if (rx == EZDOP_CMD_STREAM)     /* Stream audio samples */
177             streaming = 1;
178         else if (rx == EZDOP_CMD_STROFF)     /* Stop streaming */
179             streaming = 0;
180                 else
181                         turn_on_led();                          /* Unknown command */
182         }
183         else if (cmdbyte == 1) {
184         if (command == EZDOP_CMD_RATE) {     /* Operand is number of samples per phase increment */
185             speed = rx;
186             cmdbyte = 0;
187         }
188                 else
189                         turn_on_led();                          /* Bogus command state */
190         }
191         else
192                 turn_on_led();                                  /* Bogus command state */
193 }