checkpoint
[slipway.git] / src / edu / berkeley / obits / device / atmel / AvrDrone.c
1 // FIXMEs for SLIPWAY:\r
2 //  - use INT3 instead of INT1\r
3 //  - use PORTE[0:1] instead of PORTE[2:3]\r
4 //  - use UART0 instead of UART1\r
5 //  - clock frequency\r
6 \r
7 //\r
8 // YOU MUST COMPILE THIS WITH -O3 OR THE AVR WILL NOT BE ABLE TO KEEP UP!!!!\r
9 //\r
10 \r
11 //#define F_CPU 3960000\r
12 #define F_CPU 4000000\r
13 \r
14 #if !defined(__AVR_AT94K__)\r
15 #error you forgot to put -mmcu=at94k on the command line\r
16 #endif\r
17 \r
18 #include <avr/wdt.h>\r
19 #include <util/delay.h>\r
20 #include <avr/io.h>\r
21 #include <avr/interrupt.h>\r
22 \r
23 void initUART1(unsigned int baudRate, unsigned int doubleRate) {\r
24   UBRRHI = (((baudRate) >> 8) & 0x000F); \r
25   UBRR1  = ((baudRate) & 0x00FF); \r
26   UCSR1B |= ((1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1)); \r
27 \r
28   if (doubleRate)\r
29     UCSR1A |= (1 << U2X1);\r
30   /*\r
31   else\r
32     UCSR1A &= ~(1 << U2X1);\r
33   */\r
34 }\r
35 \r
36 #define BUFSIZE (1024)\r
37 \r
38 inline void portd(int bit, int on) {\r
39   /*\r
40   if (on) {\r
41     PORTD &= ~(1<<bit);\r
42   } else {\r
43     PORTD |= (1<<bit);\r
44   }\r
45   */\r
46 }\r
47 inline void cts(int c) {\r
48   if (c) {\r
49     PORTE &= ~(1 << 4);\r
50     portd(0, 1);\r
51   } else {\r
52     PORTE |= (1 << 4);\r
53     portd(0, 0);\r
54   }\r
55 }\r
56 \r
57 \r
58 static volatile int sending = 0;\r
59 static volatile int32_t interrupt_count = 0;\r
60 \r
61 // RECV //////////////////////////////////////////////////////////////////////////////\r
62 \r
63 char read_buf[BUFSIZE];\r
64 volatile int read_buf_head;\r
65 volatile int read_buf_tail;\r
66 char write_buf[BUFSIZE];\r
67 volatile int write_buf_head;\r
68 volatile int write_buf_tail;\r
69 \r
70 inline int inc(int x) { x++; if (x>=BUFSIZE) x=0; return x; }\r
71 inline int read_full() { return inc(read_buf_tail)==read_buf_head; }\r
72 inline int read_empty() { return read_buf_head==read_buf_tail; }\r
73 inline int read_nearlyFull() {\r
74   if (read_buf_tail==read_buf_head) return 0;\r
75   if (read_buf_tail < read_buf_head) return (read_buf_head-read_buf_tail) < (BUFSIZE/2);\r
76   return (read_buf_tail-read_buf_head) > (BUFSIZE/2);\r
77 }\r
78 \r
79 inline int write_full() { return inc(write_buf_tail)==write_buf_head; }\r
80 inline int write_empty() { return write_buf_head==write_buf_tail; }\r
81 inline int write_nearlyFull() {\r
82   if (write_buf_tail==write_buf_head) return 0;\r
83   if (write_buf_tail < write_buf_head) return (write_buf_head-write_buf_tail) < (BUFSIZE/2);\r
84   return (write_buf_tail-write_buf_head) > (BUFSIZE/2);\r
85 }\r
86 \r
87 inline char recv() {\r
88   int q;\r
89   char ret;\r
90   while(read_empty()) cts(1);\r
91   ret = read_buf[read_buf_head];\r
92   read_buf_head = inc(read_buf_head);\r
93   if (!read_nearlyFull()) cts(0);\r
94   return ret;\r
95 }\r
96 \r
97 ISR(SIG_UART1_DATA) {\r
98 \r
99   if (write_empty()) {\r
100     UCSR1B &= ~(1 << UDRIE1);\r
101     return;\r
102   }\r
103   /*\r
104   portd(1, 0);\r
105   _delay_ms(10);\r
106   portd(1, 1);\r
107   _delay_ms(10);\r
108   */\r
109   char ret = write_buf[write_buf_head];\r
110   write_buf_head = inc(write_buf_head);\r
111   UDR1 = (int)ret;\r
112 \r
113   sei();\r
114 }\r
115 \r
116 void send(char c) {\r
117 \r
118   while (write_full());\r
119 \r
120   write_buf[write_buf_tail] = c;\r
121   write_buf_tail = inc(write_buf_tail);\r
122 \r
123   UCSR1B |= (1 << UDRIE1);\r
124 \r
125   //while(!(UCSR1A & (1 << UDRE1)));           /* Wait for data Regiester to be empty */\r
126 }\r
127 \r
128 \r
129 void fpga_interrupts(int on) {\r
130   if (on/* && interrupt_count<301*/) {\r
131     //FISUA = 0x1;\r
132     FISCR = 0x80;\r
133     FISUD = 0x08;\r
134   } else {\r
135     FISUD = 0;\r
136     FISCR = 0;\r
137   }\r
138 }\r
139 \r
140 void init() {\r
141   read_buf_head = 0;\r
142   read_buf_tail = 0;\r
143   write_buf_head = 0;\r
144   write_buf_tail = 0;\r
145   EIMF  = 0xFF;                          /* Enalbe External Interrrupt*/  \r
146   DDRD = 0xFF;                           /* Configure PORTD as Output */\r
147   DDRE = 1 << 4;                         /* ability to write to E4 */\r
148   initUART1(12, 1);  //for slow board\r
149   //initUART1(1, 0);\r
150   fpga_interrupts(1);\r
151   SREG |= 0x80;\r
152   sei();\r
153 }\r
154 \r
155 \r
156 \r
157 void conf(int z, int y, int x, int d) {\r
158   FPGAX = x;\r
159   FPGAY = y;\r
160   FPGAZ = z;\r
161   FPGAD = d;\r
162 }\r
163 \r
164 void doreset() {\r
165   int i;\r
166   for(i=0; i<5; i++) {\r
167     PORTD = ~0x01;\r
168     _delay_ms(50);\r
169     PORTD = ~0x02;\r
170     _delay_ms(50);\r
171     PORTD = ~0x04;\r
172     _delay_ms(50);\r
173     PORTD = ~0x08;\r
174     _delay_ms(50);\r
175   }\r
176   PORTD = ~0x00;\r
177   wdt_enable(WDTO_250MS);\r
178   while(1) { }\r
179 }\r
180 \r
181 #define TIMERVAL 100\r
182 int portdc = 0;\r
183 ISR(SIG_FPGA_INTERRUPT15) { \r
184   PORTD = portdc++;\r
185   interrupt_count++;\r
186   //PORTD = ~(interrupt_count & 0xff);\r
187   //if (interrupt_count >= 301) fpga_interrupts(0);\r
188   //sei();\r
189   fpga_interrupts(1);\r
190 }\r
191 ISR(SIG_OVERFLOW0) { \r
192   fpga_interrupts(0);\r
193   PORTD = ~FISUA;\r
194   TCNT0 = TIMERVAL;           // load the nearest-to-one-second value  into the timer0\r
195   TIMSK |= (1<<TOIE0);        // enable the compare match1 interrupt and the timer/counter0 overflow interrupt\r
196   if (sending) UDR1 = FISUA;\r
197   fpga_interrupts(1);\r
198   sei();\r
199\r
200 void init_timer()  { \r
201   TCCR0 |= (1<<CS00);         // set the timer0 prescaler to CK\r
202   TCNT0 = TIMERVAL;           // load the nearest-to-one-second value  into the timer0\r
203   TIMSK |= (1<<TOIE0);        //enable the compare match1 interrupt and the timer/counter0 overflow interrupt\r
204\r
205 \r
206 ISR(SIG_INTERRUPT1) {   // use interrupt1 since interrupt0 is sent by the watchdog (I think)\r
207   doreset();\r
208 }\r
209 \r
210 void die() { cli(); cts(0); _delay_ms(2000); while(1) { portd(2,0); portd(2,1); } }\r
211 ISR(SIG_UART1_RECV) {\r
212   if (UCSR1A & (1 << FE1))   { portd(2,0); portd(3,1); die(); }  // framing error, lock up with LED=01\r
213   if ((UCSR1A & (1 << OR1))) { portd(2,1); portd(3,0); die(); }  // overflow; lock up with LED=10\r
214   if (read_full())           { portd(2,1); portd(3,1); die(); }  // buffer overrun\r
215   read_buf[read_buf_tail] = UDR1;\r
216   read_buf_tail = inc(read_buf_tail);\r
217   SREG |= 0x80;\r
218   sei();\r
219   if (read_nearlyFull()) cts(0);\r
220 }\r
221 \r
222 inline int hex(char c) {\r
223   if (c >= '0' && c <= '9') return (c - '0');\r
224   if (c >= 'a' && c <= 'f') return ((c - 'a') + 0xa);\r
225   if (c >= 'A' && c <= 'F') return ((c - 'A') + 0xa);\r
226   return -1;\r
227 }\r
228 \r
229 int main() {\r
230   int count;\r
231   init();\r
232   cts(0);\r
233   send('O');\r
234   send('B');\r
235   send('I');\r
236   send('T');\r
237   send('S');\r
238   send('\n');\r
239   cts(1);\r
240   int x=0, y=0, z=0;\r
241   for(;;) {\r
242     int i, d=0;\r
243     int r = recv();\r
244     switch(r) {\r
245       case 1:\r
246         z = recv();\r
247         y = recv();\r
248         x = recv();\r
249         d = recv();\r
250         portd(1,1);\r
251         conf(z, y, x, d);\r
252         portd(1,0);\r
253         break;\r
254       case 2:\r
255         fpga_interrupts(0);\r
256         portd(1,1);\r
257         send(FISUA);\r
258         portd(1,0);\r
259         fpga_interrupts(1);\r
260         break;\r
261       case 3:\r
262         init_timer();\r
263         break;\r
264       case 4:\r
265         sending = 1;\r
266         break;\r
267       case 5:\r
268         sending = 0;\r
269         break;\r
270       case 6: {\r
271         int32_t local_interrupt_count = interrupt_count;\r
272         interrupt_count = 0;\r
273         send((local_interrupt_count >> 24) & 0xff);\r
274         send((local_interrupt_count >> 16) & 0xff);\r
275         send((local_interrupt_count >>  8) & 0xff);\r
276         send((local_interrupt_count >>  0) & 0xff);\r
277         fpga_interrupts(1);\r
278         break;\r
279       }\r
280       default: {\r
281         if ((r & 0x80) == 0x80) {\r
282           switch (r & 0x44) {\r
283             case 0x44: z = recv(); break;\r
284             case 0x40: z++;        break;\r
285             case 0x04: z--;        break;\r
286           }\r
287           switch (r & 0x22) {\r
288             case 0x22: y = recv(); break;\r
289             case 0x20: y++;        break;\r
290             case 0x02: y--;        break;\r
291           }\r
292           switch (r & 0x11) {\r
293             case 0x11: x = recv(); break;\r
294             case 0x10: x++;        break;\r
295             case 0x01: x--;        break;\r
296           }\r
297           d = recv();\r
298           portd(1,1);\r
299           conf(z, y, x, d);\r
300           portd(1,0);\r
301           break;\r
302         }\r
303         die();\r
304       }\r
305     }\r
306   }\r
307   return 0;\r
308 }  \r
309 \r