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